diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Sat Apr  3 19:38:54 2004
+++ b/CREDITS	Sat Apr  3 19:38:54 2004
@@ -82,13 +82,13 @@
 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
@@ -673,11 +673,6 @@
 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 +792,6 @@
 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 +965,7 @@
 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
@@ -1677,7 +1666,7 @@
 S: Germany
 
 N: Alain L. Knaff
-E: Alain.Knaff@poboxes.com
+E: Alain.Knaff@lll.lu
 D: floppy driver
 S: 19, rue Jean l'Aveugle
 S: L-1148 Luxembourg-City
@@ -1875,6 +1864,13 @@
 S: D53424 Remagen
 S: Germany
 
+N: Colin Leroy
+E: colin@colino.net
+W: http://www.geekounet.org/
+D: PowerMac adt7467 fan driver
+S: Toulouse
+S: France
+
 N: Achim Leubner
 E: achim_leubner@adaptec.com
 D: GDT Disk Array Controller/Storage RAID controller driver
@@ -3515,9 +3511,9 @@
 W: http://www.yoshifuji.org/~hideaki/
 P: 1024D/E0620EEA 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA
 D: IPv6 and other networking related stuff
-D: USAGI/WIDE Project, The University of Tokyo
-S: Green House #102, 1-15-5, Nishikata, 
-S: Bunkyo, Tokyo 113-0024
+D: USAGI/WIDE Project, Keio University
+S: Jeunet Palace Kawasaki #1-201, 10-2, Furukawa-cho, Saiwai-ku
+S: Kawasaki, Kanagawa 212-0025
 S: Japan
 
 N: Eric Youngdale
diff -Nru a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
--- a/Documentation/DMA-API.txt	Sat Apr  3 19:38:43 2004
+++ b/Documentation/DMA-API.txt	Sat Apr  3 19:38:43 2004
@@ -279,6 +279,18 @@
 cache width is.
 
 int
+dma_mapping_error(dma_addr_t dma_addr)
+
+int
+pci_dma_mapping_error(dma_addr_t dma_addr)
+
+In some circumstances dma_map_single and dma_map_page will fail to create
+a mapping. A driver can check for these errors by testing the returned
+dma address with dma_mapping_error(). A non zero return value means the mapping
+could not be created and the driver should take appropriate action (eg
+reduce current DMA mapping usage or delay and try again later).
+
+int
 dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 	   enum dma_data_direction direction)
 int
@@ -291,6 +303,15 @@
 than <nents> passed in if the block layer determines that some
 elements of the scatter/gather list are physically adjacent and thus
 may be mapped with a single entry).
+
+Please note that the sg cannot be mapped again if it has been mapped once.
+The mapping process is allowed to destroy information in the sg.
+
+As with the other mapping interfaces, dma_map_sg can fail. When it
+does, 0 is returned and a driver must take appropriate action. It is
+critical that the driver do something, in the case of a block driver
+aborting the request or even oopsing is better than doing nothing and
+corrupting the filesystem.
 
 void
 dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
diff -Nru a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
--- a/Documentation/DMA-mapping.txt	Sat Apr  3 19:38:43 2004
+++ b/Documentation/DMA-mapping.txt	Sat Apr  3 19:38:43 2004
@@ -283,7 +283,7 @@
              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
@@ -519,7 +519,7 @@
 ends and the second one starts on a page boundary - in fact this is a huge
 advantage for cards which either cannot do scatter-gather or have very
 limited number of scatter-gather entries) and returns the actual number
-of sg entries it mapped them to.
+of sg entries it mapped them to. On failure 0 is returned.
 
 Then you should loop count times (note: this can be less than nents times)
 and use sg_dma_address() and sg_dma_len() macros where you previously
@@ -543,14 +543,30 @@
 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_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(dev, sglist, nents, direction);
+	pci_dma_sync_sg_for_device(dev, sglist, nents, direction);
 
 as appropriate.
 
@@ -590,8 +606,9 @@
 			 * 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 @@
 				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 @@
 
 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:
@@ -809,6 +841,27 @@
    deleted.
 
 2) More to come...
+
+			Handling Errors
+
+DMA address space is limited on some architectures and an allocation
+failure can be determined by:
+
+- checking if pci_alloc_consistent returns NULL or pci_map_sg returns 0
+
+- checking the returned dma_addr_t of pci_map_single and pci_map_page
+  by using pci_dma_mapping_error():
+
+	dma_addr_t dma_handle;
+
+	dma_handle = pci_map_single(dev, addr, size, direction);
+	if (pci_dma_mapping_error(dma_handle)) {
+		/*
+		 * reduce current DMA mapping usage,
+		 * delay and try again later or
+		 * reset driver.
+		 */
+	}
 
 			   Closing
 
diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile	Sat Apr  3 19:38:43 2004
+++ b/Documentation/DocBook/Makefile	Sat Apr  3 19:38:43 2004
@@ -47,7 +47,7 @@
 ###
 #External programs used
 KERNELDOC = scripts/kernel-doc
-DOCPROC   = scripts/docproc
+DOCPROC   = scripts/basic/docproc
 SPLITMAN  = $(PERL) $(srctree)/scripts/split-man
 MAKEMAN   = $(PERL) $(srctree)/scripts/makeman
 
@@ -149,12 +149,18 @@
       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 -Nru a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl
--- a/Documentation/DocBook/gadget.tmpl	Sat Apr  3 19:38:43 2004
+++ b/Documentation/DocBook/gadget.tmpl	Sat Apr  3 19:38:43 2004
@@ -454,6 +454,7 @@
 </para>
 
 !Edrivers/usb/gadget/usbstring.c
+!Edrivers/usb/gadget/config.c
 </sect1>
 
 </chapter>
diff -Nru a/Documentation/DocBook/parportbook.tmpl b/Documentation/DocBook/parportbook.tmpl
--- a/Documentation/DocBook/parportbook.tmpl	Sat Apr  3 19:38:41 2004
+++ b/Documentation/DocBook/parportbook.tmpl	Sat Apr  3 19:38:41 2004
@@ -2730,7 +2730,7 @@
 
 </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 -Nru a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
--- a/Documentation/SubmittingDrivers	Sat Apr  3 19:38:54 2004
+++ b/Documentation/SubmittingDrivers	Sat Apr  3 19:38:54 2004
@@ -51,6 +51,13 @@
 		to be useful to other communities such as BSD you may well
 		wish to release under multiple licenses.
 
+Copyright:	The copyright owner must agree to use of GPL.
+		It's best if the submitter and copyright owner
+		are the same person/entity. If not, the name of
+		the person/entity authorizing use of GPL should be
+		listed in case it's necessary to verify the will of
+		the copright owner.
+
 Interfaces:	If your driver uses existing interfaces and behaves like
 		other drivers in the same class it will be much more likely
 		to be accepted than if it invents gratuitous new ones. 
diff -Nru a/Documentation/arm/README b/Documentation/arm/README
--- a/Documentation/arm/README	Sat Apr  3 19:38:42 2004
+++ b/Documentation/arm/README	Sat Apr  3 19:38:42 2004
@@ -1,14 +1,17 @@
-			   ARM Linux 2.4
+			   ARM Linux 2.6
 			   =============
 
-    Please check ftp.arm.linux.org.uk:/pub/armlinux for latest updates.
+    Please check <ftp://ftp.arm.linux.org.uk/pub/armlinux> for
+    updates.
 
 Compilation of kernel
 ---------------------
 
   In order to compile ARM Linux, you will need a compiler capable of
-  generating ARM ELF code with GNU extensions.  GCC 2.95.1 and EGCS 1.1.2
-  are good compilers.
+  generating ARM ELF code with GNU extensions.  GCC 2.95.1, EGCS
+  1.1.2, and GCC 3.3 are known to be good compilers.  Fortunately, you
+  needn't guess.  The kernel will report an error if your compiler is
+  a recognized offender.
 
   To build ARM Linux natively, you shouldn't have to alter the ARCH = line
   in the top level Makefile.  However, if you don't have the ARM Linux ELF
@@ -147,22 +150,49 @@
   are welcome.
 
 
+CONFIG_MACH_ and CONFIG_ARCH_
+-----------------------------
+  A change was made in 2003 to the macro names for new machines.
+  Historically, CONFIG_ARCH_ was used for the bonafide architecture,
+  e.g. SA1100, as well as implementations of the architecture,
+  e.g. Assabet.  It was decided to change the implementation macros
+  to read CONFIG_MACH_ for clarity.  Moreover, a retroactive fixup has
+  not been made because it would complicate patching.
+
+  Previous registrations may be found online.
+
+    <http://www.arm.linux.org.uk/developer/machines/>
+
 Kernel entry (head-armv.S)
 --------------------------
-  The initial entry into the kernel made via head-armv.S uses architecture
-  independent code.  The architecture is selected by the value of 'r1' on
-  entry, which must be kept unique.  You can register a new architecture
-  by mailing the following details to rmk@arm.linux.org.uk  Please give
-  the mail a subject of 'Register new architecture':
-
-    Name: <name of your architecture>
-    ArchDir: <name of include/asm-arm/arch-* directory>
-    Type: <MACH_TYPE_* macro name>
-    Description:
-    <description of your architecture>
+  The initial entry into the kernel is via head-armv.S, which uses machine
+  independent code.  The machine is selected by the value of 'r1' on
+  entry, which must be kept unique.
+
+  Due to the large number of machines which the ARM port of Linux provides
+  for, we have a method to manage this which ensures that we don't end up
+  duplicating large amounts of code.
+
+  We group machine (or platform) support code into machine classes.  A
+  class typically based around one or more system on a chip devices, and
+  acts as a natural container around the actual implementations.  These
+  classes are given directories - arch/arm/mach-<class> and
+  include/asm-arm/arch-<class> - which contain the source files to
+  support the machine class.  This directories also contain any machine
+  specific supporting code.
+
+  For example, the SA1100 class is based upon the SA1100 and SA1110 SoC
+  devices, and contains the code to support the way the on-board and off-
+  board devices are used, or the device is setup, and provides that
+  machine specific "personality."
+
+  This fine-grained machine specific selection is controlled by the machine
+  type ID, which acts both as a run-time and a compile-time code selection
+  method.
+
+  You can register a new machine via the web site at:
 
-  Please follow this format - it is an automated system.  You should
-  receive a reply in short order.
+    <http://www.arm.linux.org.uk/developer/machines/>
 
 ---
-Russell King (26/01/2001)
+Russell King (15/03/2004)
diff -Nru a/Documentation/arm/memory.txt b/Documentation/arm/memory.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/arm/memory.txt	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,74 @@
+		Kernel Memory Layout on ARM Linux
+
+		Russell King <rmk@arm.linux.org.uk>
+			April 27, 2003 (2.5.68)
+
+This document describes the virtual memory layout which the Linux
+kernel uses for ARM processors.  It indicates which regions are
+free for platforms to use, and which are used by generic code.
+
+The ARM CPU is capable of addressing a maximum of 4GB virtual memory
+space, and this must be shared between user space processes, the
+kernel, and hardware devices.
+
+As the ARM architecture matures, it becomes necessary to reserve
+certain regions of VM space for use for new facilities; therefore
+this document may reserve more VM space over time.
+
+Start		End		Use
+--------------------------------------------------------------------------
+ffff8000	ffffffff	copy_user_page / clear_user_page use.
+				For SA11xx and Xscale, this is used to
+				setup a minicache mapping.
+
+ffff1000	ffff7fff	Reserved.
+				Platforms must not use this address range.
+
+ffff0000	ffff0fff	CPU vector page.
+				The CPU vectors are mapped here if the
+				CPU supports vector relocation (control
+				register V bit.)
+
+ffe00000	fffeffff	Free for platform use, not recommended.
+
+ffc00000	ffdfffff	2MB consistent memory mapping.
+				Memory returned by the consistent_alloc
+				low level function will be dynamically
+				mapped here.
+
+ff000000	ffbfffff	Free for platform use, not recommended.
+
+VMALLOC_END	ff000000	Free for platform use, recommended.
+
+VMALLOC_START	VMALLOC_END	vmalloc() / ioremap() space.
+				Memory returned by vmalloc/ioremap will
+				be dynamically placed in this region.
+				VMALLOC_START may be based upon the value
+				of the high_memory variable.
+
+PAGE_OFFSET	high_memory	Kernel direct-mapped RAM region.
+				This maps the platforms RAM, and typically
+				maps all platform RAM in a 1:1 relationship.
+
+TASK_SIZE	PAGE_OFFSET	Kernel module space
+				Kernel modules inserted via insmod are
+				placed here using dynamic mappings.
+
+00001000	TASK_SIZE	User space mappings
+				Per-thread mappings are placed here via
+				the mmap() system call.
+
+00000000	00000fff	CPU vector page / null pointer trap
+				CPUs which do not support vector remapping
+				place their vector page here.  NULL pointer
+				dereferences by both the kernel and user
+				space are also caught via this mapping.
+
+Please note that mappings which collide with the above areas may result
+in a non-bootable kernel, or may cause the kernel to (eventually) panic
+at run time.
+
+Since future CPUs may impact the kernel mapping layout, user programs
+must not access any memory which is not mapped inside their 0x0001000
+to TASK_SIZE address range.  If they wish to access these areas, they
+must set up their own mappings using open() and mmap().
diff -Nru a/Documentation/computone.txt b/Documentation/computone.txt
--- a/Documentation/computone.txt	Sat Apr  3 19:38:55 2004
+++ b/Documentation/computone.txt	Sat Apr  3 19:38:55 2004
@@ -261,7 +261,7 @@
 management of symbolic links from the devfs name space to the conventional
 names.  More details on devfs can be found on the DEVFS home site at
 <http://www.atnf.csiro.au/~rgooch/linux/> or in the file kernel
-documentation files, .../linux/Documentation/filesystems/devfs/REAME.
+documentation files, .../linux/Documentation/filesystems/devfs/README.
 
 If you are using devfs, existing devices are automatically created within
 the devfs name space.  Normal devices will be tts/F0 - tts/F255 and callout
diff -Nru a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
--- a/Documentation/crypto/api-intro.txt	Sat Apr  3 19:38:54 2004
+++ b/Documentation/crypto/api-intro.txt	Sat Apr  3 19:38:54 2004
@@ -187,6 +187,7 @@
   Brian Gladman (AES)
   Kartikey Mahendra Bhatt (CAST6)
   Jon Oberheide (ARC4)
+  Jouni Malinen (Michael MIC)
 
 SHA1 algorithm contributors:
   Jean-Francois Dive
diff -Nru a/Documentation/devices.txt b/Documentation/devices.txt
--- a/Documentation/devices.txt	Sat Apr  3 19:38:43 2004
+++ b/Documentation/devices.txt	Sat Apr  3 19:38:43 2004
@@ -1,8 +1,9 @@
 
 		       LINUX ALLOCATED DEVICES
-	     Maintained by H. Peter Anvin <device@lanana.org>
 
-		      Last revised: 3 June 2001
+	     Maintained by John Cagle <device@lanana.org>
+
+		      Last revised: 15 March 2004
 
 This list is the Linux Device List, the official registry of allocated
 device numbers and /dev directory nodes for the Linux operating
@@ -85,6 +86,7 @@
 
   0		Unnamed devices (e.g. non-device mounts)
 		  0 = reserved as null device number
+		See block major 144, 145, 146 for expansion areas.
 
   1 char	Memory devices
 		  1 = /dev/mem		Physical memory access
@@ -98,7 +100,7 @@
 		  9 = /dev/urandom	Faster, less secure random number gen.
 		 10 = /dev/aio		Asyncronous I/O notification interface
 		 11 = /dev/kmsg		Writes to this come out as printk's
-    block	RAM disk
+  1 block	RAM disk
 		  0 = /dev/ram0		First RAM disk
 		  1 = /dev/ram1		Second RAM disk
 		    ...
@@ -127,7 +129,7 @@
 		master multiplex (/dev/ptmx) to acquire a PTY on
 		demand.
   
-    block	Floppy disks
+  2 block	Floppy disks
 		  0 = /dev/fd0		Controller 0, drive 0, autodetect
 		  1 = /dev/fd1		Controller 0, drive 1, autodetect
 		  2 = /dev/fd2		Controller 0, drive 2, autodetect
@@ -193,7 +195,7 @@
 		These are the old-style (BSD) PTY devices; Unix98
 		devices are on major 136 and above.
 
-    block	First MFM, RLL and IDE hard disk/CD-ROM interface
+  3 block	First MFM, RLL and IDE hard disk/CD-ROM interface
 		  0 = /dev/hda		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdb		Slave: whole disk (or CD-ROM)
 
@@ -225,6 +227,12 @@
 		number for BSD PTY devices.  As of Linux 2.1.115, this
 		is no longer supported.	 Use major numbers 2 and 3.
 
+  4 block	Aliases for dynamically allocated major devices to be used
+		when its not possible to create the real device nodes
+		because the root filesystem is mounted read-only.
+
+                  0 = /dev/root
+
   5 char	Alternate TTY devices
 		  0 = /dev/tty		Current TTY device
 		  1 = /dev/console	System console
@@ -258,7 +266,7 @@
 	
 		NOTE: These devices permit both read and write access.
 
-    block	Loopback devices
+  7 block	Loopback devices
 		  0 = /dev/loop0	First loopback device
 		  1 = /dev/loop1	Second loopback device
 		    ...
@@ -309,7 +317,7 @@
 		ioctl()'s can be used to rewind the tape regardless of
 		the device used to access it.
 
-    block	Metadisk (RAID) devices
+  9 block	Metadisk (RAID) devices
 		  0 = /dev/md0		First metadisk group
 		  1 = /dev/md1		Second metadisk group
 		    ...
@@ -355,6 +363,7 @@
 		149 = /dev/input/mouse	Linux/SGI Irix emulation mouse
 		150 = /dev/input/keyboard Linux/SGI Irix emulation keyboard
 		151 = /dev/led		Front panel LEDs
+		152 = /dev/kpoll	Kernel Poll Driver
 		153 = /dev/mergemem	Memory merge device
 		154 = /dev/pmu		Macintosh PowerBook power manager
 		155 = /dev/isictl	MultiTech ISICom serial control
@@ -372,7 +381,7 @@
 		167 = /dev/specialix_sxctl Specialix serial control
 		168 = /dev/tcldrv	Technology Concepts serial control
 		169 = /dev/specialix_rioctl Specialix RIO serial control
-		170 = /dev/smapi	IBM Thinkpad SMAPI
+		170 = /dev/thinkpad/thinkpad	IBM Thinkpad devices
 		171 = /dev/srripc	QNX4 API IPC manager
 		172 = /dev/usemaclone	Semaphore clone device
 		173 = /dev/ipmikcs	Intelligent Platform Management
@@ -385,7 +394,7 @@
 		180 = /dev/vrbuttons	Vr41xx button input device
 		181 = /dev/toshiba	Toshiba laptop SMM support
 		182 = /dev/perfctr	Performance-monitoring counters
-		183 = /dev/intel_rng	Intel i8x0 random number generator
+		183 = /dev/hwrng	Generic random number generator
 		184 = /dev/cpu/microcode CPU microcode update interface
 		186 = /dev/atomicps	Atomic shapshot of process state data
 		187 = /dev/irnet	IrNET device
@@ -421,20 +430,27 @@
 		221 = /dev/mvista/hssdsi	Montavista PICMG hot swap system driver
 		222 = /dev/mvista/hasi		Montavista PICMG high availability
 		223 = /dev/input/uinput		User level driver support for input
-		240-255			Reserved for local use
+		224 = /dev/tpm		TCPA TPM driver
+		225 = /dev/pps		Pulse Per Second driver
+		226 = /dev/systrace	Systrace device
+		227 = /dev/mcelog	X86_64 Machine Check Exception driver
+		240-254			Reserved for local use
+		255			Reserved for MISC_DYNAMIC_MINOR
 
- 11 char	Raw keyboard device
+ 11 char	Raw keyboard device	(Linux/SPARC only)
 		  0 = /dev/kbd		Raw keyboard device
 
-		The raw keyboard device is used on Linux/SPARC only.
+ 11 char	Serial Mux device	(Linux/PA-RISC only)
+		  0 = /dev/ttyB0	First mux port
+		  1 = /dev/ttyB1	Second mux port
+		    ...
 
-    block	SCSI CD-ROM devices
-		  0 = /dev/sr0		First SCSI CD-ROM
-		  1 = /dev/sr1		Second SCSI CD-ROM
+ 11 block	SCSI CD-ROM devices
+		  0 = /dev/scd0		First SCSI CD-ROM
+		  1 = /dev/scd1		Second SCSI CD-ROM
 		    ...
 
-		The prefix /dev/scd instead of /dev/sr has been used
-		as well, and might make more sense.
+		The prefix /dev/sr (instead of /dev/scd) has been deprecated.
 
  12 char	QIC-02 tape
 		  2 = /dev/ntpqic11	QIC-11, no rewind-on-close
@@ -449,7 +465,7 @@
 		The device names specified are proposed -- if there
 		are "standard" names for these devices, please let me know.
 
-    block	MSCDEX CD-ROM callback support {2.6}
+ 12 block	MSCDEX CD-ROM callback support {2.6}
 		  0 = /dev/dos_cd0	First MSCDEX CD-ROM
 		  1 = /dev/dos_cd1	Second MSCDEX CD-ROM
 		    ...
@@ -468,7 +484,7 @@
 
 		Each device type has 5 bits (32 minors).
 
-    block	8-bit MFM/RLL/IDE controller
+ 13 block	8-bit MFM/RLL/IDE controller
 		  0 = /dev/xda		First XT disk whole disk
 		 64 = /dev/xdb		Second XT disk whole disk
 
@@ -492,7 +508,7 @@
 		 33 = /dev/patmgr1	Sequencer patch manager
 		 34 = /dev/midi02	Third MIDI port
 		 50 = /dev/midi03	Fourth MIDI port
-    block	BIOS harddrive callback support {2.6}
+ 14 block	BIOS harddrive callback support {2.6}
 		  0 = /dev/dos_hda	First BIOS harddrive whole disk
 		 64 = /dev/dos_hdb	Second BIOS harddrive whole disk
 		128 = /dev/dos_hdc	Third BIOS harddrive whole disk
@@ -508,33 +524,33 @@
 		128 = /dev/djs0		First digital joystick
 		129 = /dev/djs1		Second digital joystick
 		    ...
-    block	Sony CDU-31A/CDU-33A CD-ROM
+ 15 block	Sony CDU-31A/CDU-33A CD-ROM
 		  0 = /dev/sonycd	Sony CDU-31a CD-ROM
 
  16 char	Non-SCSI scanners
 		  0 = /dev/gs4500	Genius 4500 handheld scanner
-    block	GoldStar CD-ROM
+ 16 block	GoldStar CD-ROM
 		  0 = /dev/gscd		GoldStar CD-ROM
 
  17 char	Chase serial card
 		  0 = /dev/ttyH0	First Chase port
 		  1 = /dev/ttyH1	Second Chase port
 		    ...
-    block	Optics Storage CD-ROM
+ 17 block	Optics Storage CD-ROM
 		  0 = /dev/optcd	Optics Storage CD-ROM
 
  18 char	Chase serial card - alternate devices
 		  0 = /dev/cuh0		Callout device for ttyH0
 		  1 = /dev/cuh1		Callout device for ttyH1
 		    ...
-    block	Sanyo CD-ROM
+ 18 block	Sanyo CD-ROM
 		  0 = /dev/sjcd		Sanyo CD-ROM
 
  19 char	Cyclades serial card
 		  0 = /dev/ttyC0	First Cyclades port
 		    ...
 		 31 = /dev/ttyC31	32nd Cyclades port
-    block	"Double" compressed disk
+ 19 block	"Double" compressed disk
 		  0 = /dev/double0	First compressed disk
 		    ...
 		  7 = /dev/double7	Eighth compressed disk
@@ -549,7 +565,7 @@
 		  0 = /dev/cub0		Callout device for ttyC0
 		    ...
 		 31 = /dev/cub31	Callout device for ttyC31
-    block	Hitachi CD-ROM (under development)
+ 20 block	Hitachi CD-ROM (under development)
 		  0 = /dev/hitcd	Hitachi CD-ROM
 
  21 char	Generic SCSI access
@@ -562,7 +578,7 @@
 		the system and is counter to standard Linux
 		device-naming practice.
 
-    block	Acorn MFM hard drive interface
+ 21 block	Acorn MFM hard drive interface
 		  0 = /dev/mfma		First MFM drive whole disk
 		 64 = /dev/mfmb		Second MFM drive whole disk
 
@@ -574,7 +590,7 @@
 		  0 = /dev/ttyD0	First Digiboard port
 		  1 = /dev/ttyD1	Second Digiboard port
 		    ...
-    block	Second IDE hard disk/CD-ROM interface
+ 22 block	Second IDE hard disk/CD-ROM interface
 		  0 = /dev/hdc		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdd		Slave: whole disk (or CD-ROM)
 		
@@ -585,7 +601,7 @@
 		  0 = /dev/cud0		Callout device for ttyD0
 		  1 = /dev/cud1		Callout device for ttyD1
 		      ...
-    block	Mitsumi proprietary CD-ROM
+ 23 block	Mitsumi proprietary CD-ROM
 		  0 = /dev/mcd		Mitsumi CD-ROM
 
  24 char	Stallion serial card
@@ -601,7 +617,7 @@
 		192 = /dev/ttyE192	Stallion port 0 card 3
 		193 = /dev/ttyE193	Stallion port 1 card 3
 		    ...
-    block	Sony CDU-535 CD-ROM
+ 24 block	Sony CDU-535 CD-ROM
 		  0 = /dev/cdu535	Sony CDU-535 CD-ROM
 
  25 char	Stallion serial card - alternate devices
@@ -617,7 +633,7 @@
 		192 = /dev/cue192	Callout device for ttyE192
 		193 = /dev/cue193	Callout device for ttyE193
 		      ...
-    block	First Matsushita (Panasonic/SoundBlaster) CD-ROM
+ 25 block	First Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd0	Panasonic CD-ROM controller 0 unit 0
 		  1 = /dev/sbpcd1	Panasonic CD-ROM controller 0 unit 1
 		  2 = /dev/sbpcd2	Panasonic CD-ROM controller 0 unit 2
@@ -625,7 +641,7 @@
 
  26 char	Quanta WinVision frame grabber {2.6}
 		  0 = /dev/wvisfgrab	Quanta WinVision frame grabber
-    block	Second Matsushita (Panasonic/SoundBlaster) CD-ROM
+ 26 block	Second Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd4	Panasonic CD-ROM controller 1 unit 0
 		  1 = /dev/sbpcd5	Panasonic CD-ROM controller 1 unit 1
 		  2 = /dev/sbpcd6	Panasonic CD-ROM controller 1 unit 2
@@ -656,7 +672,7 @@
 		 37 = /dev/nrawqft1	Unit 1, no rewind-on-close, no file marks
 		 38 = /dev/nrawqft2	Unit 2, no rewind-on-close, no file marks
 		 39 = /dev/nrawqft3	Unit 3, no rewind-on-close, no file marks
-    block	Third Matsushita (Panasonic/SoundBlaster) CD-ROM
+ 27 block	Third Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd8	Panasonic CD-ROM controller 2 unit 0
 		  1 = /dev/sbpcd9	Panasonic CD-ROM controller 2 unit 1
 		  2 = /dev/sbpcd10	Panasonic CD-ROM controller 2 unit 2
@@ -667,16 +683,16 @@
 		  1 = /dev/staliomem1	Second Stallion card I/O memory
 		  2 = /dev/staliomem2	Third Stallion card I/O memory
 		  3 = /dev/staliomem3	Fourth Stallion card I/O memory
-    char	Atari SLM ACSI laser printer (68k/Atari)
+ 28 char	Atari SLM ACSI laser printer (68k/Atari)
 		  0 = /dev/slm0		First SLM laser printer
 		  1 = /dev/slm1		Second SLM laser printer
 		    ...
-    block	Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM
+ 28 block	Fourth Matsushita (Panasonic/SoundBlaster) CD-ROM
 		  0 = /dev/sbpcd12	Panasonic CD-ROM controller 3 unit 0
 		  1 = /dev/sbpcd13	Panasonic CD-ROM controller 3 unit 1
 		  2 = /dev/sbpcd14	Panasonic CD-ROM controller 3 unit 2
 		  3 = /dev/sbpcd15	Panasonic CD-ROM controller 3 unit 3
-    block	ACSI disk (68k/Atari)
+ 28 block	ACSI disk (68k/Atari)
 		  0 = /dev/ada		First ACSI disk whole disk
 		 16 = /dev/adb		Second ACSI disk whole disk
 		 32 = /dev/adc		Third ACSI disk whole disk
@@ -693,23 +709,41 @@
 		    ...
 		 31 = /dev/fb31		32nd frame buffer
 
-    block	Aztech/Orchid/Okano/Wearnes CD-ROM
+ 29 block	Aztech/Orchid/Okano/Wearnes CD-ROM
 		  0 = /dev/aztcd	Aztech CD-ROM
 
  30 char	iBCS-2 compatibility devices
 		  0 = /dev/socksys	Socket access
 		  1 = /dev/spx		SVR3 local X interface
-		  2 = /dev/inet/arp	Network access
-		  2 = /dev/inet/icmp	Network access
-		  2 = /dev/inet/ip	Network access
-		  2 = /dev/inet/udp	Network access
-		  2 = /dev/inet/tcp	Network access
-
-		Additionally, iBCS-2 requires /dev/nfsd to be a link
-		to /dev/socksys, and /dev/X0R to be a link to
-		/dev/null.
+		 32 = /dev/inet/ip	Network access
+		 33 = /dev/inet/icmp
+		 34 = /dev/inet/ggp
+		 35 = /dev/inet/ipip
+		 36 = /dev/inet/tcp
+		 37 = /dev/inet/egp
+		 38 = /dev/inet/pup
+		 39 = /dev/inet/udp
+		 40 = /dev/inet/idp
+		 41 = /dev/inet/rawip
+
+		Additionally, iBCS-2 requires the following links:
+
+		/dev/ip -> /dev/inet/ip
+		/dev/icmp -> /dev/inet/icmp
+		/dev/ggp -> /dev/inet/ggp
+		/dev/ipip -> /dev/inet/ipip
+		/dev/tcp -> /dev/inet/tcp
+		/dev/egp -> /dev/inet/egp
+		/dev/pup -> /dev/inet/pup
+		/dev/udp -> /dev/inet/udp
+		/dev/idp -> /dev/inet/idp
+		/dev/rawip -> /dev/inet/rawip
+		/dev/inet/arp -> /dev/inet/udp
+		/dev/inet/rip -> /dev/inet/udp
+		/dev/nfsd -> /dev/socksys
+		/dev/X0R -> /dev/null (? apparently not required ?)
 
-    block	Philips LMS CM-205 CD-ROM
+ 30 block	Philips LMS CM-205 CD-ROM
 		  0 = /dev/cm205cd	Philips LMS CM-205 CD-ROM
 
 		/dev/lmscd is an older name for this device.  This
@@ -718,7 +752,7 @@
  31 char	MPU-401 MIDI
 		  0 = /dev/mpu401data	MPU-401 data port
 		  1 = /dev/mpu401stat	MPU-401 status port
-    block	ROM/flash memory card
+ 31 block	ROM/flash memory card
 		  0 = /dev/rom0		First ROM card (rw)
 		      ...
 		  7 = /dev/rom7		Eighth ROM card (rw)
@@ -741,14 +775,14 @@
 		  0 = /dev/ttyX0	First Specialix port
 		  1 = /dev/ttyX1	Second Specialix port
 		    ...
-    block	Philips LMS CM-206 CD-ROM
+ 32 block	Philips LMS CM-206 CD-ROM
 		  0 = /dev/cm206cd	Philips LMS CM-206 CD-ROM
 
  33 char	Specialix serial card - alternate devices
 		  0 = /dev/cux0		Callout device for ttyX0
 		  1 = /dev/cux1		Callout device for ttyX1
 		    ...
-    block	Third IDE hard disk/CD-ROM interface
+ 33 block	Third IDE hard disk/CD-ROM interface
 		  0 = /dev/hde		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdf		Slave: whole disk (or CD-ROM)
 
@@ -766,7 +800,7 @@
 		/dev/sc1 for /dev/scc0, /dev/sc2 for /dev/scc1, and so
 		on.
 
-    block	Fourth IDE hard disk/CD-ROM interface
+ 34 block	Fourth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdg		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdh		Slave: whole disk (or CD-ROM)
 		
@@ -786,7 +820,7 @@
 		129 = /dev/smpte1	Second MIDI port, SMPTE timed
 		130 = /dev/smpte2	Third MIDI port, SMPTE timed
 		131 = /dev/smpte3	Fourth MIDI port, SMPTE timed
-    block	Slow memory ramdisk
+ 35 block	Slow memory ramdisk
 		  0 = /dev/slram	Slow memory ramdisk
 
  36 char	Netlink support
@@ -796,7 +830,7 @@
 		 16 = /dev/tap0		First Ethertap device
 		    ...
 		 31 = /dev/tap15	16th Ethertap device
-    block	MCA ESDI hard disk
+ 36 block	MCA ESDI hard disk
 		  0 = /dev/eda		First ESDI disk whole disk
 		 64 = /dev/edb		Second ESDI disk whole disk
 		    ...
@@ -814,7 +848,7 @@
 
 		Currently, only one IDE tape drive is supported.
 
-    block	Zorro II ramdisk
+ 37 block	Zorro II ramdisk
 		  0 = /dev/z2ram	Zorro II ramdisk
 
  38 char	Myricom PCI Myrinet board
@@ -826,7 +860,7 @@
 		and "user level packet I/O."  This board is also
 		accessible as a standard networking "eth" device.
 
-    block	Reserved for Linux/AP+
+ 38 block	Reserved for Linux/AP+
 
  39 char	ML-16P experimental I/O board
 		  0 = /dev/ml16pa-a0	First card, first analog channel
@@ -846,11 +880,11 @@
 		 50 = /dev/ml16pb-c1	Second card, second counter/timer
 		 51 = /dev/ml16pb-c2	Second card, third counter/timer
 		      ...
-    block	Reserved for Linux/AP+
+ 39 block	Reserved for Linux/AP+
 
  40 char	Matrox Meteor frame grabber {2.6}
 		  0 = /dev/mmetfgrab	Matrox Meteor frame grabber
-    block	Syquest EZ135 parallel port removable drive
+ 40 block	Syquest EZ135 parallel port removable drive
 		  0 = /dev/eza		Parallel EZ135 drive, whole disk
 
 		This device is obsolete and will be removed in a
@@ -861,14 +895,15 @@
 
  41 char	Yet Another Micro Monitor
 		  0 = /dev/yamm		Yet Another Micro Monitor
-    block	MicroSolutions BackPack parallel port CD-ROM
+ 41 block	MicroSolutions BackPack parallel port CD-ROM
 		  0 = /dev/bpcd		BackPack CD-ROM
 
 		This device is obsolete and will be removed in a
 		future version of Linux.  It has been replaced with
 		the parallel port ATAPI CD-ROM driver at major number 46.
 
- 42		Demo/sample use
+ 42 char	Demo/sample use
+ 42 block	Demo/sample use
 
 		This number is intended for use in sample code, as
 		well as a general "example" device number.  It
@@ -885,7 +920,7 @@
 		  0 = /dev/ttyI0	First virtual modem
 		    ...
 		 63 = /dev/ttyI63	64th virtual modem
-    block	Network block devices
+ 43 block	Network block devices
 		  0 = /dev/nb0		First network block device
 		  1 = /dev/nb1		Second network block device
 		    ...
@@ -901,7 +936,7 @@
 		  0 = /dev/cui0		Callout device for ttyI0
 		    ...
 		 63 = /dev/cui63	Callout device for ttyI63
-    block	Flash Translatio Layer (FTL) filesystems
+ 44 block	Flash Translation Layer (FTL) filesystems
 		  0 = /dev/ftla		FTL on first Memory Technology Device
 		 16 = /dev/ftlb		FTL on second Memory Technology Device
 		 32 = /dev/ftlc		FTL on third Memory Technology Device
@@ -925,7 +960,7 @@
 		191 = /dev/ippp63	64th SyncPPP device
 
 		255 = /dev/isdninfo	ISDN monitor interface
-    block	Parallel port IDE disk devices
+ 45 block	Parallel port IDE disk devices
 		  0 = /dev/pda		First parallel port IDE disk
 		 16 = /dev/pdb		Second parallel port IDE disk
 		 32 = /dev/pdc		Third parallel port IDE disk
@@ -939,7 +974,7 @@
 		  0 = /dev/ttyR0	First Rocketport port
 		  1 = /dev/ttyR1	Second Rocketport port
 		    ...
-    block	Parallel port ATAPI CD-ROM devices
+ 46 block	Parallel port ATAPI CD-ROM devices
 		  0 = /dev/pcd0		First parallel port ATAPI CD-ROM
 		  1 = /dev/pcd1		Second parallel port ATAPI CD-ROM
 		  2 = /dev/pcd2		Third parallel port ATAPI CD-ROM
@@ -949,7 +984,7 @@
 		  0 = /dev/cur0		Callout device for ttyR0
 		  1 = /dev/cur1		Callout device for ttyR1
 		    ...
-    block	Parallel port ATAPI disk devices
+ 47 block	Parallel port ATAPI disk devices
 		  0 = /dev/pf0		First parallel port ATAPI disk
 		  1 = /dev/pf1		Second parallel port ATAPI disk
 		  2 = /dev/pf2		Third parallel port ATAPI disk
@@ -962,7 +997,7 @@
 		  0 = /dev/ttyL0	First RISCom port
 		  1 = /dev/ttyL1	Second RISCom port
 		    ...
-    block	Mylex DAC960 PCI RAID controller; first controller
+ 48 block	Mylex DAC960 PCI RAID controller; first controller
 		  0 = /dev/rd/c0d0	First disk, whole disk
 		  8 = /dev/rd/c0d1	Second disk, whole disk
 		    ...
@@ -978,7 +1013,7 @@
 		  0 = /dev/cul0		Callout device for ttyL0
 		  1 = /dev/cul1		Callout device for ttyL1
 		    ...
-    block	Mylex DAC960 PCI RAID controller; second controller
+ 49 block	Mylex DAC960 PCI RAID controller; second controller
 		  0 = /dev/rd/c1d0	First disk, whole disk
 		  8 = /dev/rd/c1d1	Second disk, whole disk
 		    ...
@@ -988,17 +1023,17 @@
 
  50 char	Reserved for GLINT
 
-    block	Mylex DAC960 PCI RAID controller; third controller
+ 50 block	Mylex DAC960 PCI RAID controller; third controller
 		  0 = /dev/rd/c2d0	First disk, whole disk
 		  8 = /dev/rd/c2d1	Second disk, whole disk
 		    ...
 		248 = /dev/rd/c2d31	32nd disk, whole disk
 
- 51 char	Baycom radio modem
+ 51 char	Baycom radio modem OR Radio Tech BIM-XXX-RS232 radio modem
 		  0 = /dev/bc0		First Baycom radio modem
 		  1 = /dev/bc1		Second Baycom radio modem
 		    ...
-    block	Mylex DAC960 PCI RAID controller; fourth controller
+ 51 block	Mylex DAC960 PCI RAID controller; fourth controller
 		  0 = /dev/rd/c3d0	First disk, whole disk
 		  8 = /dev/rd/c3d1	Second disk, whole disk
 		    ...
@@ -1011,7 +1046,7 @@
 		  1 = /dev/dcbri1	Second DataComm card
 		  2 = /dev/dcbri2	Third DataComm card
 		  3 = /dev/dcbri3	Fourth DataComm card
-    block	Mylex DAC960 PCI RAID controller; fifth controller
+ 52 block	Mylex DAC960 PCI RAID controller; fifth controller
 		  0 = /dev/rd/c4d0	First disk, whole disk
 		  8 = /dev/rd/c4d1	Second disk, whole disk
 		    ...
@@ -1033,7 +1068,7 @@
 		Domain Interface and ICD is the commercial interface
 		by P&E.
 
-    block	Mylex DAC960 PCI RAID controller; sixth controller
+ 53 block	Mylex DAC960 PCI RAID controller; sixth controller
 		  0 = /dev/rd/c5d0	First disk, whole disk
 		  8 = /dev/rd/c5d1	Second disk, whole disk
 		    ...
@@ -1050,7 +1085,7 @@
 		<mseritan@ottonel.pub.ro> to transfer data from Holter
 		24-hour heart monitoring equipment.
 
-    block	Mylex DAC960 PCI RAID controller; seventh controller
+ 54 block	Mylex DAC960 PCI RAID controller; seventh controller
 		  0 = /dev/rd/c6d0	First disk, whole disk
 		  8 = /dev/rd/c6d1	Second disk, whole disk
 		    ...
@@ -1060,7 +1095,7 @@
 
  55 char	DSP56001 digital signal processor
 		  0 = /dev/dsp56k	First DSP56001
-    block	Mylex DAC960 PCI RAID controller; eigth controller
+ 55 block	Mylex DAC960 PCI RAID controller; eigth controller
 		  0 = /dev/rd/c7d0	First disk, whole disk
 		  8 = /dev/rd/c7d1	Second disk, whole disk
 		    ...
@@ -1074,7 +1109,7 @@
 		Additional devices will be added to this number, all
 		starting with /dev/adb.
 
-    block	Fifth IDE hard disk/CD-ROM interface
+ 56 block	Fifth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdi		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdj		Slave: whole disk (or CD-ROM)
 
@@ -1086,7 +1121,7 @@
 		  1 = /dev/ttyP1	Second ESP port
 		    ...
 
-    block	Sixth IDE hard disk/CD-ROM interface
+ 57 block	Sixth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdk		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdl		Slave: whole disk (or CD-ROM)
 
@@ -1097,12 +1132,12 @@
 		  0 = /dev/cup0		Callout device for ttyP0
 		  1 = /dev/cup1		Callout device for ttyP1
 		    ...
-    block	Reserved for logical volume manager
+ 58 block	Reserved for logical volume manager
 
  59 char	sf firewall package
 		  0 = /dev/firewall	Communication with sf kernel module
 
-    block	Generic PDA filesystem device
+ 59 block	Generic PDA filesystem device
 		  0 = /dev/pda0		First PDA device
 		  1 = /dev/pda1		Second PDA device
 		    ...
@@ -1115,14 +1150,30 @@
 
 		NAMING CONFLICT -- PROPOSED REVISED NAME /dev/rpda0 etc
 
- 60-63		LOCAL/EXPERIMENTAL USE
+ 60-63 char	LOCAL/EXPERIMENTAL USE
+ 60-63 block	LOCAL/EXPERIMENTAL USE
 		Allocated for local/experimental use.  For devices not
 		assigned official numbers, these ranges should be
-		used, in order to avoid conflicting with future assignments.
+		used in order to avoid conflicting with future assignments.
 
  64 char	ENskip kernel encryption package
 		  0 = /dev/enskip	Communication with ENskip kernel module
 
+ 64 block	Scramdisk/DriveCrypt encrypted devices
+		  0 = /dev/scramdisk/master    Master node for ioctls
+		  1 = /dev/scramdisk/1         First encrypted device
+		  2 = /dev/scramdisk/2         Second encrypted device
+		  ...
+		255 = /dev/scramdisk/255       255th encrypted device
+
+		The filename of the encrypted container and the passwords
+		are sent via ioctls (using the sdmount tool) to the master
+		node which then activates them via one of the
+		/dev/scramdisk/x nodes for loopback mounting (all handled
+		through the sdmount tool).
+
+		Requested by: andy@scramdisklinux.org
+
  65 char	Sundance "plink" Transputer boards
 		  0 = /dev/plink0	First plink device
 		  1 = /dev/plink1	Second plink device
@@ -1144,10 +1195,10 @@
 		This is a commercial driver; contact James Howes
 		<jth@prosig.demon.co.uk> for information.
 
-    block	SCSI disk devices (16-31)
-		  0 = /dev/sdq		16th SCSI disk whole disk
-		 16 = /dev/sdr		17th SCSI disk whole disk
-		 32 = /dev/sds		18th SCSI disk whole disk
+ 65 block	SCSI disk devices (16-31)
+		  0 = /dev/sdq		17th SCSI disk whole disk
+		 16 = /dev/sdr		18th SCSI disk whole disk
+		 32 = /dev/sds		19th SCSI disk whole disk
 		    ...
 		240 = /dev/sdaf		32nd SCSI disk whole disk
 
@@ -1160,7 +1211,7 @@
 		  1 = /dev/yppcpci1	Second YARC card
 		    ...
 
-    block	SCSI disk devices (32-47)
+ 66 block	SCSI disk devices (32-47)
 		  0 = /dev/sdag		33th SCSI disk whole disk
 		 16 = /dev/sdah		34th SCSI disk whole disk
 		 32 = /dev/sdai		35th SCSI disk whole disk
@@ -1176,7 +1227,7 @@
 
 		See http://www.coda.cs.cmu.edu for information about Coda.
 
-    block	SCSI disk devices (48-63)
+ 67 block	SCSI disk devices (48-63)
 		  0 = /dev/sdaw		49th SCSI disk whole disk
 		 16 = /dev/sdax		50th SCSI disk whole disk
 		 32 = /dev/sday		51st SCSI disk whole disk
@@ -1197,10 +1248,10 @@
 		ISDN CAPI 2.0 driver for use with CAPI 2.0
 		applications; currently supports the AVM B1 card.
 
-    block	SCSI disk devices (64-79)
-		  0 = /dev/sdbm		64th SCSI disk whole disk
-		 16 = /dev/sdbn		65th SCSI disk whole disk
-		 32 = /dev/sdbo		66th SCSI disk whole disk
+ 68 block	SCSI disk devices (64-79)
+		  0 = /dev/sdbm		65th SCSI disk whole disk
+		 16 = /dev/sdbn		66th SCSI disk whole disk
+		 32 = /dev/sdbo		67th SCSI disk whole disk
 		    ...
 		240 = /dev/sdcb		80th SCSI disk whole disk
 
@@ -1211,7 +1262,7 @@
  69 char	MA16 numeric accelerator card
 		  0 = /dev/ma16		Board memory access
 
-    block	SCSI disk devices (80-95)
+ 69 block	SCSI disk devices (80-95)
 		  0 = /dev/sdcc		81st SCSI disk whole disk
 		 16 = /dev/sdcd		82nd SCSI disk whole disk
 		 32 = /dev/sdce		83th SCSI disk whole disk
@@ -1231,7 +1282,7 @@
 		 65 = /dev/apsasync	Async command interface
 		128 = /dev/apsmon	Monitor interface
 
-    block	SCSI disk devices (96-111)
+ 70 block	SCSI disk devices (96-111)
 		  0 = /dev/sdcs		97th SCSI disk whole disk
 		 16 = /dev/sdct		98th SCSI disk whole disk
 		 32 = /dev/sdcu		99th SCSI disk whole disk
@@ -1260,7 +1311,7 @@
 		    ...
 		255 = /dev/ttyF255	IntelliPort II board 3, port 63
 
-    block	SCSI disk devices (112-127)
+ 71 block	SCSI disk devices (112-127)
 		  0 = /dev/sddi		113th SCSI disk whole disk
 		 16 = /dev/sddj		114th SCSI disk whole disk
 		 32 = /dev/sddk		115th SCSI disk whole disk
@@ -1289,7 +1340,7 @@
 		    ...
 		255 = /dev/cuf255	Callout device for ttyF255
 
-    block	Compaq Intelligent Drive Array, first controller
+ 72 block	Compaq Intelligent Drive Array, first controller
 		  0 = /dev/ida/c0d0	First logical drive whole disk
 		 16 = /dev/ida/c0d1	Second logical drive whole disk
 		    ...
@@ -1309,7 +1360,7 @@
 		 12 = /dev/ip2ipl3	Loadware device for board 3
 		 13 = /dev/ip2stat3	Status device for board 3
 
-    block	Compaq Intelligent Drive Array, second controller
+ 73 block	Compaq Intelligent Drive Array, second controller
 		  0 = /dev/ida/c1d0	First logical drive whole disk
 		 16 = /dev/ida/c1d1	Second logical drive whole disk
 		    ...
@@ -1327,7 +1378,7 @@
 		Currently for Dolphin Interconnect Solutions' PCI-SCI
 		bridge.
 
-    block	Compaq Intelligent Drive Array, third controller
+ 74 block	Compaq Intelligent Drive Array, third controller
 		  0 = /dev/ida/c2d0	First logical drive whole disk
 		 16 = /dev/ida/c2d1	Second logical drive whole disk
 		    ...
@@ -1344,7 +1395,7 @@
 		  8 = /dev/ttyW8	First IO8+ port, second card
 		    ...
 
-    block	Compaq Intelligent Drive Array, fourth controller
+ 75 block	Compaq Intelligent Drive Array, fourth controller
 		  0 = /dev/ida/c3d0	First logical drive whole disk
 		 16 = /dev/ida/c3d1	Second logical drive whole disk
 		    ...
@@ -1361,7 +1412,7 @@
 		  8 = /dev/cuw8		Callout device for ttyW8
 		    ...
 
-    block	Compaq Intelligent Drive Array, fifth controller
+ 76 block	Compaq Intelligent Drive Array, fifth controller
 		  0 = /dev/ida/c4d0	First logical drive whole disk
 		 16 = /dev/ida/c4d1	Second logical drive whole disk
 		    ...
@@ -1375,7 +1426,7 @@
  77 char	ComScire Quantum Noise Generator
 		  0 = /dev/qng		ComScire Quantum Noise Generator
 
-    block	Compaq Intelligent Drive Array, sixth controller
+ 77 block	Compaq Intelligent Drive Array, sixth controller
 		  0 = /dev/ida/c5d0	First logical drive whole disk
 		 16 = /dev/ida/c5d1	Second logical drive whole disk
 		    ...
@@ -1391,7 +1442,7 @@
 		  1 = /dev/ttyM1	Second PAM modem
 		    ...
 
-    block	Compaq Intelligent Drive Array, seventh controller
+ 78 block	Compaq Intelligent Drive Array, seventh controller
 		  0 = /dev/ida/c6d0	First logical drive whole disk
 		 16 = /dev/ida/c6d1	Second logical drive whole disk
 		    ...
@@ -1407,7 +1458,7 @@
 		  1 = /dev/cum1		Callout device for ttyM1
 		    ...
 
-    block	Compaq Intelligent Drive Array, eigth controller
+ 79 block	Compaq Intelligent Drive Array, eigth controller
 		  0 = /dev/ida/c7d0	First logical drive whole disk
 		 16 = /dev/ida/c7d1	Second logical drive whole disk
 		    ...
@@ -1421,7 +1472,7 @@
  80 char	Photometrics AT200 CCD camera
 		  0 = /dev/at200	Photometrics AT200 CCD camera
 
-    block	I2O hard disk
+ 80 block	I2O hard disk
 		  0 = /dev/i2o/hda	First I2O hard disk, whole disk
 		 16 = /dev/i2o/hdb	Second I2O hard disk, whole disk
 		    ...
@@ -1445,7 +1496,7 @@
 		    ...
 		255 = /dev/vbi31	Vertical blank interrupt
 
-    block	I2O hard disk
+ 81 block	I2O hard disk
 		  0 = /dev/i2o/hdq	17th I2O hard disk, whole disk
 		 16 = /dev/i2o/hdr	18th I2O hard disk, whole disk
 		    ...
@@ -1463,7 +1514,7 @@
 		The driver and documentation may be obtained from
 		http://www.proximity.com.au/~brian/winradio/
 
-    block	I2O hard disk
+ 82 block	I2O hard disk
 		  0 = /dev/i2o/hdag	33rd I2O hard disk, whole disk
 		 16 = /dev/i2o/hdah	34th I2O hard disk, whole disk
 		    ...
@@ -1480,7 +1531,7 @@
 		Devices for the driver contained in the VideoteXt package.
 		More information on http://home.pages.de/~videotext/
 
-    block	I2O hard disk
+ 83 block	I2O hard disk
 		  0 = /dev/i2o/hdaw	49th I2O hard disk, whole disk
 		 16 = /dev/i2o/hdax	50th I2O hard disk, whole disk
 		    ...
@@ -1494,7 +1545,7 @@
 		  0 = /dev/ihcp0	First Greensheet port
 		  1 = /dev/ihcp1	Second Greensheet port
 
-    block	I2O hard disk
+ 84 block	I2O hard disk
 		  0 = /dev/i2o/hdbm	65th I2O hard disk, whole disk
 		 16 = /dev/i2o/hdbn	66th I2O hard disk, whole disk
 		    ...
@@ -1510,7 +1561,7 @@
 		  2 = /dev/qcntl1	Second device pushed
 		    ...
 
-    block	I2O hard disk
+ 85 block	I2O hard disk
 		  0 = /dev/i2o/hdcc	81st I2O hard disk, whole disk
 		 16 = /dev/i2o/hdcd	82nd I2O hard disk, whole disk
 		    ...
@@ -1525,7 +1576,7 @@
 		  1 = /dev/sch1		Second SCSI media changer
 		    ...
 
-    block	I2O hard disk
+ 86 block	I2O hard disk
 		  0 = /dev/i2o/hdcs	97th I2O hard disk, whole disk
 		 16 = /dev/i2o/hdct	98th I2O hard disk, whole disk
 		    ...
@@ -1540,7 +1591,7 @@
 		  1 = /dev/controla1	Second device on chain
 		    ...
 
-    block	I2O hard disk
+ 87 block	I2O hard disk
 		  0 = /dev/i2o/hddi	113rd I2O hard disk, whole disk
 		 16 = /dev/i2o/hddj	114th I2O hard disk, whole disk
 		    ...
@@ -1555,7 +1606,7 @@
 		  1 = /dev/comx1	COMX channel 1
 		    ...
 
-    block	Seventh IDE hard disk/CD-ROM interface
+ 88 block	Seventh IDE hard disk/CD-ROM interface
 		  0 = /dev/hdm		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdn		Slave: whole disk (or CD-ROM)
 
@@ -1567,7 +1618,7 @@
 		  1 = /dev/i2c-1	Second I2C adapter
 		    ...
 
-    block	Eighth IDE hard disk/CD-ROM interface
+ 89 block	Eighth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdo		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdp		Slave: whole disk (or CD-ROM)
 
@@ -1581,7 +1632,7 @@
 		 30 = /dev/mtd15	16th MTD (rw)
 		 31 = /dev/mtdr15	16th MTD (ro)
 
-    block	Ninth IDE hard disk/CD-ROM interface
+ 90 block	Ninth IDE hard disk/CD-ROM interface
 		  0 = /dev/hdq		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdr		Slave: whole disk (or CD-ROM)
 
@@ -1593,7 +1644,7 @@
 		  1 = /dev/can1		Second CAN-Bus controller
 		    ...
 
-    block	Tenth IDE hard disk/CD-ROM interface
+ 91 block	Tenth IDE hard disk/CD-ROM interface
 		  0 = /dev/hds		Master: whole disk (or CD-ROM)
 		 64 = /dev/hdt		Slave: whole disk (or CD-ROM)
 
@@ -1602,7 +1653,7 @@
 
  92 char	Reserved for ith Kommunikationstechnik MIC ISDN card
 
-    block	PPDD encrypted disk driver
+ 92 block	PPDD encrypted disk driver
 		  0 = /dev/ppdd0	First encrypted disk
 		  1 = /dev/ppdd1	Second encrypted disk
 		    ...
@@ -1619,7 +1670,7 @@
 		129 = /dev/isccctl1	Second Smart Capture Card control
 		    ...
 
-    block	NAND Flash Translation Layer filesystem
+ 93 block	NAND Flash Translation Layer filesystem
 		  0 = /dev/nftla	First NFTL layer
 		 16 = /dev/nftlb	Second NFTL layer
 		    ...
@@ -1630,16 +1681,11 @@
 		  1 = /dev/dcxx1	Second capture card
 		    ...
 
-    block	IBM S/390 DASD block storage
-		  0 = /dev/dasda	First DASD device, major
-		  1 = /dev/dasda1	First DASD device, block 1
-		  2 = /dev/dasda2	First DASD device, block 2
-		  3 = /dev/dasda3	First DASD device, block 3
-		  4 = /dev/dasdb	Second DASD device, major
-		  5 = /dev/dasdb1	Second DASD device, block 1
-		  6 = /dev/dasdb2	Second DASD device, block 2
-		  7 = /dev/dasdb3	Second DASD device, block 3
+ 94 block	Inverse NAND Flash Translation Layer
+		  0 = /dev/inftla	First INFTL layer
+		 16 = /dev/inftlb	Second INFTL layer
 		    ...
+		240 = /dev/inftlp	16th INTFL layer
 
  95 char	IP filter
 		  0 = /dev/ipl		Filter control device/log file
@@ -1648,9 +1694,15 @@
 		  3 = /dev/ipauth	Authentication control device/log file
 		    ...		
 
-    block	IBM S/390 VM/ESA minidisk
-		  0 = /dev/mnda		First VM/ESA minidisk
-		  1 = /dev/mndb		Second VM/ESA minidisk
+ 95 block	IBM S/390 DASD block storage
+		  0 = /dev/dasd0	First DASD device, major
+		  1 = /dev/dasd0a	First DASD device, block 1
+		  2 = /dev/dasd0b	First DASD device, block 2
+		  3 = /dev/dasd0c	First DASD device, block 3
+		  4 = /dev/dasd1	Second DASD device, major
+		  5 = /dev/dasd1a	Second DASD device, block 1
+		  6 = /dev/dasd1b	Second DASD device, block 2
+		  7 = /dev/dasd1c	Second DASD device, block 3
 		    ...
 
  96 char	Parallel port ATAPI tape devices
@@ -1661,6 +1713,11 @@
 		129 = /dev/npt1		Second p.p. ATAPI tape, no rewind
 		    ...
 
+ 96 block	IBM S/390 VM/ESA minidisk
+		  0 = /dev/msd0		First VM/ESA minidisk
+		  1 = /dev/msd1		Second VM/ESA minidisk
+		    ...
+
  97 char	Parallel port generic ATAPI interface
 		  0 = /dev/pg0		First parallel port ATAPI device
 		  1 = /dev/pg1		Second parallel port ATAPI device
@@ -1670,7 +1727,7 @@
 		These devices support the same API as the generic SCSI
 		devices.
 
-    block	Packet writing for CD/DVD devices
+ 97 block	Packet writing for CD/DVD devices
 		  0 = /dev/pktcdvd0	First packet-writing module
 		  1 = /dev/pktcdvd1	Second packet-writing module
 		    ...
@@ -1682,7 +1739,7 @@
 
 		See http://stm.lbl.gov/comedi or http://www.llp.fu-berlin.de/.
 
-    block	User-mode virtual block device
+ 98 block	User-mode virtual block device
 		  0 = /dev/ubd0		First user-mode block device
 		  1 = /dev/ubd1		Second user-mode block device
 		    ...
@@ -1694,7 +1751,7 @@
 		  1 = /dev/parport1	Second parallel port
 		    ...
 
-    block	JavaStation flash disk
+ 99 block	JavaStation flash disk
 		  0 = /dev/jsfd		JavaStation flash disk
 
 100 char	Telephony for Linux
@@ -1708,7 +1765,7 @@
 		    ...
 		 16 = /dev/mdsp16	16th DSP board I/O controls
 
-    block	AMI HyperDisk RAID controller
+101 block	AMI HyperDisk RAID controller
 		  0 = /dev/amiraid/ar0	First array whole disk
 		 16 = /dev/amiraid/ar1	Second array whole disk
 		    ...
@@ -1727,7 +1784,7 @@
 		  2 = /dev/tlk2		Third Teletext decoder
 		  3 = /dev/tlk3		Fourth Teletext decoder
 
-    block	Compressed block device
+102 block	Compressed block device
 		  0 = /dev/cbd/a	First compressed block device, whole device
 		 16 = /dev/cbd/b	Second compressed block device, whole device
 		    ...
@@ -1747,12 +1804,12 @@
 		to the arla announce mailing list by sending a mail to
 		<arla-announce-request@stacken.kth.se>.
 
-    block	Audit device
+103 block	Audit device
 		  0 = /dev/audit	Audit device
 
 104 char	Flash BIOS support
 
-    block	Compaq Next Generation Drive Array, first controller
+104 block	Compaq Next Generation Drive Array, first controller
 		  0 = /dev/cciss/c0d0	First logical drive, whole disk
 		 16 = /dev/cciss/c0d1	Second logical drive, whole disk
 		    ...
@@ -1767,7 +1824,7 @@
 		  1 = /dev/ttyV1	Second VS-1000 port
 		    ...
 
-    block	Compaq Next Generation Drive Array, second controller
+105 block	Compaq Next Generation Drive Array, second controller
 		  0 = /dev/cciss/c1d0	First logical drive, whole disk
 		 16 = /dev/cciss/c1d1	Second logical drive, whole disk
 		    ...
@@ -1782,7 +1839,7 @@
 		  1 = /dev/cuv1		Second VS-1000 port
 		    ...
 
-    block	Compaq Next Generation Drive Array, third controller
+106 block	Compaq Next Generation Drive Array, third controller
 		  0 = /dev/cciss/c2d0	First logical drive, whole disk
 		 16 = /dev/cciss/c2d1	Second logical drive, whole disk
 		    ...
@@ -1795,7 +1852,7 @@
 107 char	3Dfx Voodoo Graphics device
 		  0 = /dev/3dfx		Primary 3Dfx graphics device
 
-    block	Compaq Next Generation Drive Array, fourth controller
+107 block	Compaq Next Generation Drive Array, fourth controller
 		  0 = /dev/cciss/c3d0	First logical drive, whole disk
 		 16 = /dev/cciss/c3d1	Second logical drive, whole disk
 		    ...
@@ -1808,7 +1865,7 @@
 108 char	Device independent PPP interface
 		  0 = /dev/ppp		Device independent PPP interface
 
-    block	Compaq Next Generation Drive Array, fifth controller
+108 block	Compaq Next Generation Drive Array, fifth controller
 		  0 = /dev/cciss/c4d0	First logical drive, whole disk
 		 16 = /dev/cciss/c4d1	Second logical drive, whole disk
 		    ...
@@ -1820,7 +1877,7 @@
 
 109 char	Reserved for logical volume manager
 
-    block	Compaq Next Generation Drive Array, sixth controller
+109 block	Compaq Next Generation Drive Array, sixth controller
 		  0 = /dev/cciss/c5d0	First logical drive, whole disk
 		 16 = /dev/cciss/c5d1	Second logical drive, whole disk
 		    ...
@@ -1835,7 +1892,7 @@
 		  1 = /dev/srnd1	Second miroMEDIA Surround board
 		    ...
 
-    block	Compaq Next Generation Drive Array, seventh controller
+110 block	Compaq Next Generation Drive Array, seventh controller
 		  0 = /dev/cciss/c6d0	First logical drive, whole disk
 		 16 = /dev/cciss/c6d1	Second logical drive, whole disk
 		    ...
@@ -1850,7 +1907,7 @@
 		  1 = /dev/av1		Second A/V card
 		    ...
 
-    block	Compaq Next Generation Drive Array, eigth controller
+111 block	Compaq Next Generation Drive Array, eigth controller
 		  0 = /dev/cciss/c7d0	First logical drive, whole disk
 		 16 = /dev/cciss/c7d1	Second logical drive, whole disk
 		    ...
@@ -1868,14 +1925,14 @@
 		There is currently a device-naming conflict between
 		these and PAM multimodems (major 78).
 
-    block	IBM iSeries virtual disk
+112 block	IBM iSeries virtual disk
 		  0 = /dev/iseries/vda	First virtual disk, whole disk
 		  8 = /dev/iseries/vdb	Second virtual disk, whole disk
 		    ...
 		200 = /dev/iseries/vdz	26th virtual disk, whole disk
 		208 = /dev/iseries/vdaa	27th virtual disk, whole disk
 		    ...
-		240 = /dev/iseries/vdaf	32nd virtual disk, whole disk
+		248 = /dev/iseries/vdaf	32nd virtual disk, whole disk
 
 		Partitions are handled in the same way as for IDE
 		disks (see major number 3) except that the limit on
@@ -1886,7 +1943,7 @@
 		  1 = /dev/cum1		Callout device for ttyM1
 		    ...
 
-    block	IBM iSeries virtual CD-ROM
+113 block	IBM iSeries virtual CD-ROM
 
 		  0 = /dev/iseries/vcda	First virtual CD-ROM
 		  1 = /dev/iseries/vcdb	Second virtual CD-ROM
@@ -1905,13 +1962,69 @@
 		I/O access to the board, the /dev/isex0 nodes command
 		nodes used to control the board.
 
-115 char	Console driver speaker
-		  0 = /dev/speaker	Speaker device file
+114 block       IDE BIOS powered software RAID interfaces such as the
+                Promise Fastrak
 
-		Plays music using IBM BASIC style strings.
+                  0 = /dev/ataraid/d0
+                  1 = /dev/ataraid/d0p1
+                  2 = /dev/ataraid/d0p2
+                  ...
+                 16 = /dev/ataraid/d1
+                 17 = /dev/ataraid/d1p1
+                 18 = /dev/ataraid/d1p2
+                  ...
+                255 = /dev/ataraid/d15p15
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+115 char	TI link cable devices (115 was formerly the console driver speaker)
+		  0 = /dev/tipar0    Parallel cable on first parallel port
+		  ...
+		  7 = /dev/tipar7    Parallel cable on seventh parallel port
+
+		  8 = /dev/tiser0    Serial cable on first serial port
+		  ...
+		 15 = /dev/tiser7    Serial cable on seventh serial port
+
+		 16 = /dev/tiusb0    First USB cable
+		  ...
+		 47 = /dev/tiusb31   32nd USB cable
+
+115 block       NetWare (NWFS) Devices (0-255)
+
+                The NWFS (NetWare) devices are used to present a
+                collection of NetWare Mirror Groups or NetWare
+                Partitions as a logical storage segment for
+                use in mounting NetWare volumes.  A maximum of
+                256 NetWare volumes can be supported in a single
+                machine.
+
+                http://www.kernel.org/pub/linux/kernel/people/jmerkey/nwfs
+
+                0 = /dev/nwfs/v0    First NetWare (NWFS) Logical Volume
+                1 = /dev/nwfs/v1    Second NetWare (NWFS) Logical Volume
+                2 = /dev/nwfs/v2    Third NetWare (NWFS) Logical Volume
+                      ...
+                255 = /dev/nwfs/v255    Last NetWare (NWFS) Logical Volume
 
 116 char	Advanced Linux Sound Driver (ALSA)
 
+116 block       MicroMemory battery backed RAM adapter (NVRAM)
+                Supports 16 boards, 15 paritions each.
+                Requested by neilb at cse.unsw.edu.au.
+
+		 0 = /dev/umem/d0      Whole of first board
+		 1 = /dev/umem/d0p1    First partition of first board
+		 2 = /dev/umem/d0p2    Second partition of first board
+		15 = /dev/umem/d0p15   15th partition of first board
+
+		16 = /dev/umem/d1      Whole of second board
+		17 = /dev/umem/d1p1    First partition of second board
+		    ...
+		255= /dev/umem/d15p15  15th partition of 16th board.
+
 117 char	COSA/SRP synchronous serial card
 		  0 = /dev/cosa0c0	1st board, 1st channel
 		  1 = /dev/cosa0c1	1st board, 2nd channel
@@ -1920,6 +2033,32 @@
 		 17 = /dev/cosa1c1	2nd board, 2nd channel
 		    ...
 
+117 block       Enterprise Volume Management System (EVMS)
+
+                The EVMS driver uses a layered, plug-in model to provide
+                unparalleled flexibility and extensibility in managing
+                storage.  This allows for easy expansion or customization
+                of various levels of volume management.  Requested by
+                Mark Peloquin (peloquin at us.ibm.com).
+
+                Note: EVMS populates and manages all the devnodes in
+                /dev/evms.
+
+                http://sf.net/projects/evms
+
+                  0 = /dev/evms/block_device   EVMS block device
+                  1 = /dev/evms/legacyname1    First EVMS legacy device
+                  2 = /dev/evms/legacyname2    Second EVMS legacy device
+                    ...
+                    Both ranges can grow (down or up) until they meet.
+                    ...
+                254 = /dev/evms/EVMSname2      Second EVMS native device
+                255 = /dev/evms/EVMSname1      First EVMS native device
+
+                Note: legacyname(s) are derived from the normal legacy
+                device names.  For example, /dev/hda5 would become
+                /dev/evms/hda5.
+
 118 char	Solidum ???
 		  0 = /dev/solnp0
 		  1 = /dev/solnp1
@@ -1933,14 +2072,114 @@
 		  1 = /dev/vnet1	2nd virtual network
 		    ...
 
-120-127		LOCAL/EXPERIMENTAL USE
+120-127 char	LOCAL/EXPERIMENTAL USE
+120-127 block	LOCAL/EXPERIMENTAL USE
+		Allocated for local/experimental use.  For devices not
+		assigned official numbers, these ranges should be
+		used in order to avoid conflicting with future assignments.
 
-128-135	char	Unix98 PTY masters
+128-135 char	Unix98 PTY masters
 
 		These devices should not have corresponding device
 		nodes; instead they should be accessed through the
 		/dev/ptmx cloning interface.
 
+
+128 block       SCSI disk devices (128-143)
+                  0 = /dev/sddy         129th SCSI disk whole disk
+                 16 = /dev/sddz         130th SCSI disk whole disk
+                 32 = /dev/sdea         131th SCSI disk whole disk
+                    ...
+                240 = /dev/sden         144th SCSI disk whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+
+129 block       SCSI disk devices (144-159)
+                  0 = /dev/sdeo         145th SCSI disk whole disk
+                 16 = /dev/sdep         146th SCSI disk whole disk
+                 32 = /dev/sdeq         147th SCSI disk whole disk
+                    ...
+                240 = /dev/sdfd         160th SCSI disk whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+
+130 block       SCSI disk devices (160-175)
+                  0 = /dev/sdfe         161st SCSI disk whole disk
+                 16 = /dev/sdff         162nd SCSI disk whole disk
+                 32 = /dev/sdfg         163rd SCSI disk whole disk
+                    ...
+                240 = /dev/sdft         176th SCSI disk whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+131 block       SCSI disk devices (176-191)
+                  0 = /dev/sdfu         177th SCSI disk whole disk
+                 16 = /dev/sdfv         178th SCSI disk whole disk
+                 32 = /dev/sdfw         179th SCSI disk whole disk
+                    ...
+                240 = /dev/sdgj         192nd SCSI disk whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+
+132 block       SCSI disk devices (192-207)
+                  0 = /dev/sdgk         193rd SCSI disk whole disk
+                 16 = /dev/sdgl         194th SCSI disk whole disk
+                 32 = /dev/sdgm         195th SCSI disk whole disk
+                    ...
+                240 = /dev/sdgz         208th SCSI disk whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+
+133 block       SCSI disk devices (208-223)
+                  0 = /dev/sdha         209th SCSI disk whole disk
+                 16 = /dev/sdhb         210th SCSI disk whole disk
+                 32 = /dev/sdhc         211th SCSI disk whole disk
+                    ...
+                240 = /dev/sdhp         224th SCSI disk whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+
+134 block       SCSI disk devices (224-239)
+                  0 = /dev/sdhq         225th SCSI disk whole disk
+                 16 = /dev/sdhr         226th SCSI disk whole disk
+                 32 = /dev/sdhs         227th SCSI disk whole disk
+                    ...
+                240 = /dev/sdif         240th SCSI disk whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+
+135 block       SCSI disk devices (240-255)
+                  0 = /dev/sdig         241st SCSI disk whole disk
+                 16 = /dev/sdih         242nd SCSI disk whole disk
+                 32 = /dev/sdih         243rd SCSI disk whole disk
+                    ...
+                240 = /dev/sdiv         256th SCSI disk whole disk
+
+		Partitions are handled in the same way as for IDE
+		disks (see major number 3) except that the limit on
+		partitions is 15.
+
+
 136-143 char	Unix98 PTY slaves
 		  0 = /dev/pts/0	First Unix98 pseudo-TTY
 		  1 = /dev/pts/1	Second Unix98 pesudo-TTY
@@ -1953,6 +2192,70 @@
 		*most* distributions the appropriate options are
 		"mode=0620,gid=<gid of the "tty" group>".)
 
+136 block	Mylex DAC960 PCI RAID controller; ninth controller
+		  0 = /dev/rd/c8d0	First disk, whole disk
+		  8 = /dev/rd/c8d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c8d31	32nd disk, whole disk
+
+		Partitions are handled as for major 48.
+
+137 block	Mylex DAC960 PCI RAID controller; tenth controller
+		  0 = /dev/rd/c9d0	First disk, whole disk
+		  8 = /dev/rd/c9d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c9d31	32nd disk, whole disk
+
+		Partitions are handled as for major 48.
+
+138 block	Mylex DAC960 PCI RAID controller; eleventh controller
+		  0 = /dev/rd/c10d0	First disk, whole disk
+		  8 = /dev/rd/c10d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c10d31	32nd disk, whole disk
+
+		Partitions are handled as for major 48.
+
+139 block	Mylex DAC960 PCI RAID controller; twelfth controller
+		  0 = /dev/rd/c11d0	First disk, whole disk
+		  8 = /dev/rd/c11d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c11d31	32nd disk, whole disk
+
+		Partitions are handled as for major 48.
+
+140 block	Mylex DAC960 PCI RAID controller; thirteenth controller
+		  0 = /dev/rd/c12d0	First disk, whole disk
+		  8 = /dev/rd/c12d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c12d31	32nd disk, whole disk
+
+		Partitions are handled as for major 48.
+
+141 block	Mylex DAC960 PCI RAID controller; fourteenth controller
+		  0 = /dev/rd/c13d0	First disk, whole disk
+		  8 = /dev/rd/c13d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c13d31	32nd disk, whole disk
+
+		Partitions are handled as for major 48.
+
+142 block	Mylex DAC960 PCI RAID controller; fifteenth controller
+		  0 = /dev/rd/c14d0	First disk, whole disk
+		  8 = /dev/rd/c14d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c14d31	32nd disk, whole disk
+
+		Partitions are handled as for major 48.
+
+143 block	Mylex DAC960 PCI RAID controller; sixteenth controller
+		  0 = /dev/rd/c15d0	First disk, whole disk
+		  8 = /dev/rd/c15d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c15d31	32nd disk, whole disk
+
+		Partitions are handled as for major 48.
+
 144 char	Encapsulated PPP
 		  0 = /dev/pppox0	First PPP over Ethernet
 		    ...
@@ -1963,6 +2266,10 @@
 		The SST 5136-DN DeviceNet interface driver has been
 		relocated to major 183 due to an unfortunate conflict.
 
+144 block	Expansion Area #1 for more non-device (e.g. NFS) mounts
+		  0 = mounted device 256
+		255 = mounted device 511
+
 145 char	SAM9407-based soundcard
 		  0 = /dev/sam0_mixer
 		  1 = /dev/sam0_sequencer
@@ -1984,12 +2291,20 @@
 		addons, which are sam9407 specific.  OSS can be
 		operated simultaneously, taking care of the codec.
 
+145 block	Expansion Area #2 for more non-device (e.g. NFS) mounts
+		  0 = mounted device 512
+		255 = mounted device 767
+
 146 char	SYSTRAM SCRAMNet mirrored-memory network
 		  0 = /dev/scramnet0	First SCRAMNet device
 		  1 = /dev/scramnet1	Second SCRAMNet device
 		    ...
 
-147 char	Aueral Semiconductor Vortex Audio device
+146 block	Expansion Area #3 for more non-device (e.g. NFS) mounts
+		  0 = mounted device 768
+		255 = mounted device 1023
+
+147 char	Aureal Semiconductor Vortex Audio device
 		  0 = /dev/aureal0	First Aureal Vortex
 		  1 = /dev/aureal1	Second Aureal Vortex
 		    ...
@@ -2014,6 +2329,22 @@
 		  1 = /dev/dpti1	Second DPT I2O adapter
 		    ...
 
+152 char	EtherDrive Control Device
+		  0 = /dev/etherd/ctl	Connect/Disconnect an EtherDrive
+		  1 = /dev/etherd/err	Monitor errors
+		  2 = /dev/etherd/raw	Raw AoE packet monitor
+
+152 block	EtherDrive Block Devices
+		  0 = /dev/etherd/0	EtherDrive 0
+		    ...
+		255 = /dev/etherd/255	EtherDrive 255
+
+153 char	SPI Bus Interface (sometimes referred to as MicroWire)
+		  0 = /dev/spi0		First SPI device on the bus
+		  1 = /dev/spi1		Second SPI device on the bus
+		    ...
+		 15 = /dev/spi15	Sixteenth SPI device on the bus
+
 154 char	Specialix RIO serial card
 		  0 = /dev/ttySR0	First RIO port
 		    ...
@@ -2046,6 +2377,21 @@
 		  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,16 +2400,28 @@
 		 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
 		  2 = /dev/raw/raw2	Second raw I/O device
 		    ...
 
-163 char	Radio Tech BIM-XXX-RS232 radio modem
-		  0 = /dev/bimrt0	First BIM radio modem
-		  1 = /dev/bimrt1	Second BIM radio modem
-		    ...
+163 char	UNASSIGNED (was Radio Tech BIM-XXX-RS232 radio modem - see 51)
 
 164 char	Chase Research AT/PCI-Fast serial card
 		  0 = /dev/ttyCH0	AT/PCI-Fast board 0, port 0
@@ -2175,6 +2533,9 @@
 		    ...
 		 63 = /dev/usb/scanner15 16th USB scanner
 		 64 = /dev/usb/rio500	Diamond Rio 500
+		 65 = /dev/usb/usblcd	USBLCD Interface (info@usblcd.de)
+		 66 = /dev/usb/cpad0	Synaptics cPad (mouse/LCD)
+
 
 181 char	Conrad Electronic parallel port radio clocks
 		  0 = /dev/pcfclock0	First Conrad radio clock
@@ -2295,9 +2656,10 @@
 		  0 = /dev/vx/rdsk/*/*		First volume
 		  1 = /dev/vx/rdsk/*/*		Second volume
 		    ...
-    block	Veritas volume manager (VxVM) volumes
+
+199 block	Veritas volume manager (VxVM) volumes
 		  0 = /dev/vx/dsk/*/*		First volume
-		  1 = /dev/vx/dsk/*/*		First volume
+		  1 = /dev/vx/dsk/*/*		Second volume
 		    ...
 
 		The namespace in these directories is maintained by
@@ -2315,7 +2677,7 @@
 		  0 = /dev/vx/rdmp/*		First multipath device
 		  1 = /dev/vx/rdmp/*		Second multipath device
 		    ...
-    block	Veritas VxVM dynamic multipathing driver
+201 block	Veritas VxVM dynamic multipathing driver
 		  0 = /dev/vx/dmp/*		First multipath device
 		  1 = /dev/vx/dmp/*		Second multipath device
 		    ...
@@ -2469,6 +2831,26 @@
 		  1 = /dev/addinum/cpci1500/1	Second CPCI1500 card
 		    ...
 
+212 char	LinuxTV.org DVB driver subsystem
+
+		  0 = /dev/dvb/adapter0/video0    first video decoder of first card
+		  1 = /dev/dvb/adapter0/audio0    first audio decoder of first card
+		  2 = /dev/dvb/adapter0/sec0      (obsolete/unused)
+		  3 = /dev/dvb/adapter0/frontend0 first frontend device of first card
+		  4 = /dev/dvb/adapter0/demux0    first demux device of first card
+		  5 = /dev/dvb/adapter0/dvr0      first digital video recoder device of first card
+		  6 = /dev/dvb/adapter0/ca0       first common access port of first card
+		  7 = /dev/dvb/adapter0/net0      first network device of first card
+		  8 = /dev/dvb/adapter0/osd0      first on-screen-display device of first card
+		  9 = /dev/dvb/adapter0/video1    second video decoder of first card
+		    ...
+		 64 = /dev/dvb/adapter1/video0    first video decoder of second card
+		    ...
+		128 = /dev/dvb/adapter2/video0    first video decoder of third card
+		    ...
+		196 = /dev/dvb/adapter3/video0    first video decoder of fourth card
+
+
 216 char	USB BlueTooth devices
 		  0 = /dev/ttyUB0		First USB BlueTooth device
 		  1 = /dev/ttyUB1		Second USB BlueTooth device
@@ -2575,9 +2957,14 @@
 
 231-239		UNASSIGNED
 
-240-254		LOCAL/EXPERIMENTAL USE
+240-254 char	LOCAL/EXPERIMENTAL USE
+240-254 block	LOCAL/EXPERIMENTAL USE
+		Allocated for local/experimental use.  For devices not
+		assigned official numbers, these ranges should be
+		used in order to avoid conflicting with future assignments.
 
-255		RESERVED
+255 char	RESERVED
+255 block	RESERVED
 
 		This major is reserved to assist the expansion to a
 		larger number space.  No device nodes with this major
diff -Nru a/Documentation/filesystems/udf.txt b/Documentation/filesystems/udf.txt
--- a/Documentation/filesystems/udf.txt	Sat Apr  3 19:38:55 2004
+++ b/Documentation/filesystems/udf.txt	Sat Apr  3 19:38:55 2004
@@ -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 @@
 	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 @@
 -------------------------------------------------------------------------------
 
 
-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 -Nru a/Documentation/filesystems/ufs.txt b/Documentation/filesystems/ufs.txt
--- a/Documentation/filesystems/ufs.txt	Sat Apr  3 19:38:54 2004
+++ b/Documentation/filesystems/ufs.txt	Sat Apr  3 19:38:54 2004
@@ -20,6 +20,9 @@
 	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 -Nru a/Documentation/i2c/sysfs-interface b/Documentation/i2c/sysfs-interface
--- a/Documentation/i2c/sysfs-interface	Sat Apr  3 19:38:41 2004
+++ b/Documentation/i2c/sysfs-interface	Sat Apr  3 19:38:41 2004
@@ -3,22 +3,44 @@
 
 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 @@
 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 @@
 
 -------------------------------------------------------------------------
 
-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 @@
 		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 -Nru a/Documentation/i386/zero-page.txt b/Documentation/i386/zero-page.txt
--- a/Documentation/i386/zero-page.txt	Sat Apr  3 19:38:42 2004
+++ b/Documentation/i386/zero-page.txt	Sat Apr  3 19:38:42 2004
@@ -1,7 +1,7 @@
-Summary of empty_zero_page layout (kernel point of view)
+Summary of boot_params layout (kernel point of view)
      ( collected by Hans Lermen and Martin Mares )
  
-The contents of empty_zero_page are used to pass parameters from the
+The contents of boot_params are used to pass parameters from the
 16-bit realmode code of the kernel to the 32-bit part. References/settings
 to it mainly are in:
 
@@ -75,10 +75,4 @@
 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
-
-0x800	string, 2K max	COMMAND_LINE, the kernel commandline as
-			copied using CL_OFFSET.
-			Note: this will be copied once more by setup.c
-			into a local buffer which is only 256 bytes long.
-			( #define COMMAND_LINE_SIZE 256 )
+0x600 - 0x7eb		EDDBUF (setup.S) for edd data
diff -Nru a/Documentation/ide.txt b/Documentation/ide.txt
--- a/Documentation/ide.txt	Sat Apr  3 19:38:45 2004
+++ b/Documentation/ide.txt	Sat Apr  3 19:38:45 2004
@@ -249,8 +249,6 @@
  "hdx=scsi"		: the return of the ide-scsi flag, this is useful for
  			  allowing ide-floppy, ide-tape, and ide-cdrom|writers
  			  to use ide-scsi emulation on a device specific option.
-				
- "hdxlun=xx"		: set the drive last logical unit
 
  "idebus=xx"		: inform IDE driver of VESA/PCI bus speed in MHz,
 			  where "xx" is between 20 and 66 inclusive,
diff -Nru a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt
--- a/Documentation/input/joystick-parport.txt	Sat Apr  3 19:38:56 2004
+++ b/Documentation/input/joystick-parport.txt	Sat Apr  3 19:38:56 2004
@@ -434,7 +434,7 @@
   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 @@
 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 @@
 	 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 @@
 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 -Nru a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt
--- a/Documentation/input/joystick.txt	Sat Apr  3 19:38:55 2004
+++ b/Documentation/input/joystick.txt	Sat Apr  3 19:38:55 2004
@@ -111,7 +111,7 @@
 	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 @@
 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 @@
   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 -Nru a/Documentation/java.txt b/Documentation/java.txt
--- a/Documentation/java.txt	Sat Apr  3 19:38:45 2004
+++ b/Documentation/java.txt	Sat Apr  3 19:38:45 2004
@@ -22,7 +22,7 @@
    the kernel (CONFIG_BINFMT_MISC) and set it up properly.
    If you choose to compile it as a module, you will have
    to insert it manually with modprobe/insmod, as kmod
-   can not easy be supported with binfmt_misc. 
+   can not easily be supported with binfmt_misc. 
    Read the file 'binfmt_misc.txt' in this directory to know
    more about the configuration process.
 
diff -Nru a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
--- a/Documentation/kbuild/makefiles.txt	Sat Apr  3 19:38:54 2004
+++ b/Documentation/kbuild/makefiles.txt	Sat Apr  3 19:38:54 2004
@@ -119,7 +119,7 @@
 		obj-y += foo.o
 
 	This tell kbuild that there is one object in that directory named
-	foo.o. foo.o will be build from foo.c or foo.S.
+	foo.o. foo.o will be built from foo.c or foo.S.
 
 	If foo.o shall be built as a module, the variable obj-m is used.
 	Therefore the following pattern is often used:
@@ -334,7 +334,7 @@
 
 --- 3.9 Dependency tracking
 
-	Kbuild track dependencies on the following:
+	Kbuild tracks dependencies on the following:
 	1) All prerequisite files (both *.c and *.h)
 	2) CONFIG_ options used in all prerequisite files
 	3) Command-line used to compile target
@@ -411,7 +411,7 @@
 --- 4.2 Composite Host Programs
 
 	Host programs can be made up based on composite objects.
-	The syntax used to define composite objetcs for host programs is
+	The syntax used to define composite objects for host programs is
 	similar to the syntax used for kernel objects.
 	$(<executeable>-objs) list all objects used to link the final
 	executable.
@@ -811,7 +811,7 @@
 
     extra-y
 
-	extra-y specify additional targets created in current
+	extra-y specify additional targets created in the current
 	directory, in addition to any targets specified by obj-*.
 
 	Listing all targets in extra-y is required for two purposes:
@@ -829,7 +829,7 @@
 	
 --- 6.6 Commands useful for building a boot image
 
-	Kbuild provide a few macros that are useful when building a
+	Kbuild provides a few macros that are useful when building a
 	boot image.
 
     if_changed
@@ -872,7 +872,7 @@
 		$(obj)/setup $(obj)/bootsect: %: %.o FORCE
 			$(call if_changed,ld)
 
-	In this example there is two possible targets, requiring different
+	In this example there are two possible targets, requiring different
 	options to the linker. the linker options are specified using the
 	LDFLAGS_$@ syntax - one for each potential target.
 	$(targets) are assinged all potential targets, herby kbuild knows
diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt	Sat Apr  3 19:38:57 2004
+++ b/Documentation/kernel-parameters.txt	Sat Apr  3 19:38:57 2004
@@ -98,11 +98,13 @@
 				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 }
-			level   Force PIC-mode SCI to Level Trigger (default)
-			edge    Force PIC-mode SCI to Edge Trigge
+	acpi_sci=	[HW,ACPI] ACPI System Control Interrupt trigger mode
+			Format: { level | edge |  high | low }
 
 	acpi_irq_balance	[HW,ACPI] ACPI will balance active IRQs
 				default in APIC mode
@@ -116,6 +118,10 @@
 	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 +160,15 @@
 			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 +191,18 @@
 
 	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 +304,11 @@
 	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 +402,14 @@
 	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 +636,9 @@
 
 	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 +1183,6 @@
 			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 +1205,13 @@
 	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 -Nru a/Documentation/mono.txt b/Documentation/mono.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/mono.txt	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,66 @@
+               Mono(tm) Binary Kernel Support for Linux
+               -----------------------------------------
+
+To configure Linux to automatically execute Mono-based .NET binaries
+(in the form of .exe files) without the need to use the mono CLR
+wrapper, you can use the BINFMT_MISC kernel support.
+
+This will allow you to execute Mono-based .NET binaries just like any
+other program after you have done the following:
+
+1) You MUST FIRST install the Mono CLR support, either by downloading
+   a binary package, a source tarball or by installing from CVS. Binary
+   packages for several distributions can be found at:
+
+	http://go-mono.com/download.html
+
+   Instructions for compiling Mono can be found at:
+
+	http://www.go-mono.com/compiling.html
+
+   Once the Mono CLR support has been installed, just check that
+   /usr/bin/mono (which could be located elsewhere, for example
+   /usr/local/bin/mono) is working.
+
+2) You have to compile BINFMT_MISC either as a module or into
+   the kernel (CONFIG_BINFMT_MISC) and set it up properly.
+   If you choose to compile it as a module, you will have
+   to insert it manually with modprobe/insmod, as kmod
+   can not be easily supported with binfmt_misc. 
+   Read the file 'binfmt_misc.txt' in this directory to know
+   more about the configuration process.
+
+3) Add the following enries to /etc/rc.local or similar script
+   to be run at system startup:
+
+# Insert BINFMT_MISC module into the kernel
+if [ ! -e /proc/sys/fs/binfmt_misc/register ]; then
+        /sbin/modprobe binfmt_misc
+	# Some distributions, like Fedora Core, perform
+	# the following command automatically when the
+	# binfmt_misc module is loaded into the kernel.
+	# Thus, it is possible that the following line
+	# is not needed at all. Look at /etc/modprobe.conf
+	# to check whether this is applicable or not.
+        mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
+fi
+
+# Register support for .NET CLR binaries
+if [ -e /proc/sys/fs/binfmt_misc/register ]; then
+	# Replace /usr/bin/mono with the correct pathname to
+	# the Mono CLR runtime (usually /usr/local/bin/mono
+	# when compiling from sources or CVS).
+        echo ':CLR:M::MZ::/usr/bin/mono:' > /proc/sys/fs/binfmt_misc/register
+else
+        echo "No binfmt_misc support"
+        exit 1
+fi
+
+4) Check that .exe binaries can be ran without the need of a
+   wrapper script, simply by launching the .exe file directly
+   from a command prompt, for example:
+
+	/usr/bin/xsd.exe
+
+   NOTE: If this fails with a permission denied error, check
+         that the .exe file has execute permissions.
diff -Nru a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
--- a/Documentation/networking/bonding.txt	Sat Apr  3 19:38:42 2004
+++ b/Documentation/networking/bonding.txt	Sat Apr  3 19:38:42 2004
@@ -55,8 +55,9 @@
 --------------------------------------
 This version of the bonding driver requires updated ifenslave program. The
 original one from extreme-linux and beowulf will not work. Kernels 2.4.12
-and above include the updated version of ifenslave.c in Documentation/network
-directory. For older kernels, please follow the links at the end of this file.
+and above include the updated version of ifenslave.c in
+Documentation/networking directory. For older kernels, please follow the
+links at the end of this file.
 
 IMPORTANT!!!  If you are running on Redhat 7.1 or greater, you need
 to be careful because /usr/include/linux is no longer a symbolic link
diff -Nru a/Documentation/networking/e100.txt b/Documentation/networking/e100.txt
--- a/Documentation/networking/e100.txt	Sat Apr  3 19:38:55 2004
+++ b/Documentation/networking/e100.txt	Sat Apr  3 19:38:55 2004
@@ -1,7 +1,7 @@
 Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
 ==============================================================
 
-November 19, 2002
+March 15, 2004
 
 
 Contents
@@ -9,9 +9,6 @@
 
 - In This Release
 - Supported Adapters
-- Command Line Parameters
-- CPU Cycle Saver
-- Additional Configurations
 - Support
 
 
@@ -19,64 +16,13 @@
 ===============
 
 This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of
-Adapters, version 2.2.x.  This driver includes support for Itanium(TM)-based 
+Adapters, version 3.x.x.  This driver includes support for Itanium(TM)-based 
 systems.
 
 
 Supported Adapters
 ==================
 
-The following Intel network adapters are compatible with the drivers 
-in this release:
-
-Controller  Adapter Name                            Board IDs
-----------  ------------                            ---------
-
-82558       PRO/100+ PCI Adapter                    668081-xxx, 689661-xxx
-
-82558       PRO/100+ Management Adapter             691334-xxx, 701738-xxx,
-                                                    721383-xxx
-
-82558       PRO/100+ Dual Port Server Adapter       714303-xxx, 711269-xxx, 
-                                                    A28276-xxx
-
-82558       PRO/100+ PCI Server Adapter             710550-xxx
-
-82550       PRO/100 S Server Adapter                752438-xxx (82550)
-82559                                               A56831-xxx, A10563-xxx,
-                                                    A12171-xxx, A12321-xxx, 
-                                                    A12320-xxx, A12170-xxx
-                                                    748568-xxx (82559)
-                                                    748565-xxx (82559)
-
-
-82550       PRO/100 S Desktop Adapter               751767-xxx (82550)
-82559                                               748592-xxx, A12167-xxx, 
-                                                    A12318-xxx, A12317-xxx, 
-                                                    A12165-xxx
-                                                    748569-xxx (82559)
-
-
-
-82559       PRO/100+ Server Adapter                 729757-xxx
-
-82559       PRO/100 S Management Adapter            748566-xxx, 748564-xxx
-
-82550       PRO/100 S Dual Port Server Adapter      A56831-xxx
-
-82551       PRO/100 M Desktop Adapter               A80897-xxx
-
-            PRO/100 S Advanced Management Adapter   747842-xxx, 745171-xxx
-
-CNR         PRO/100 VE Desktop Adapter              A10386-xxx, A10725-xxx, 
-                                                    A23801-xxx, A19716-xxx
-
-
-            PRO/100 VM Desktop Adapter              A14323-xxx, A19725-xxx, 
-                                                    A23801-xxx, A22220-xxx, 
-                                                    A23796-xxx
-   
-
 To verify that your adapter is supported, find the board ID number on the 
 adapter. Look for a label that has a barcode and a number in the format 
 A12345-001. Match this to the list of numbers above.
@@ -89,143 +35,6 @@
 For the latest Intel PRO/100 network driver for Linux, see:
 
   http://downloadfinder.intel.com/scripts-df/support_intel.asp
-
-
-Command Line Parameters
-=======================
-
-If the driver is built as a module, the  following optional parameters are 
-used by entering them on the command line with the modprobe or insmod command
-using this syntax:
-
-     modprobe e100 [<option>=<VAL1>,<VAL2>,...]
-
-     insmod e100 [<option>=<VAL1>,<VAL2>,...] 
-
-For example, with two Intel PRO/100 PCI adapters, entering:
-	
-     modprobe e100 TxDescriptors=32,128
-
-loads the e100 driver with 32 TX resources for the first adapter and 128 TX 
-resources for the second adapter. This configuration favors the second 
-adapter. The driver supports up to 16 network adapters concurrently.
-
-The default value for each parameter is generally the recommended setting,
-unless otherwise noted.
-
-NOTE: Giving any command line option the value "-1" causes the driver to use 
-      the appropriate default value for that option, as if no value was 
-      specified.
-
-
-BundleMax
-Valid Range: 1-65535
-Default Value: 6
-   This parameter holds the maximum number of small packets (less than 128
-   bytes) in a bundle. Suggested values range from 2 to 10. See "CPU Cycle 
-   Saver."
-
-BundleSmallFr
-Valid Range: 0-1 (0=off, 1=on)
-Default Value: 0
-   The value 1 (on) causes small packets (less than 128 bytes) to be bundled. 
-   See "CPU Cycle Saver."
-
-e100_speed_duplex
-Valid Range: 0-4 (1=10half;2=10full;3=100half;4=100full)
-Default Value: 0
-   The default value of 0 sets the adapter to auto-negotiate. Other values
-   set the adapter to forced speed and duplex. 
-   Example usage: insmod e100.o e100_speed_duplex=4,4 (for two adapters)
-
-flow_control
-Valid Range: 0-1 (0=off, 1=on)
-Default Value: 0
-   This parameter controls the automatic generation(Tx) and response(Rx) to 
-   Ethernet PAUSE frames. flow_control should NOT be set to 1 when the 
-   adapter is connected to an interface that does not support Ethernet PAUSE 
-   frames and when the e100_speed_duplex parameter is NOT set to zero. 
-
-IntDelay
-Valid Range: 0-65535 (0=off)
-Default Value: 1536
-   This parameter holds the number of time units (in adapter terminology)
-   until the adapter generates an interrupt. The recommended value for 
-   IntDelay is 1536 (upon initialization). Suggested values range from 
-   512 to 2048. See "CPU Cycle Saver."
-
-IFS
-Valid Range: 0-1 (0=off, 1=on)
-Default Value: 1
-  Inter Frame Spacing (IFS) aims to reduce the number of Ethernet frame
-  collisions by altering the time between frame transmissions. When IFS is 
-  enabled the driver tries to find an optimal IFS value. It is used only at 
-  half duplex.
-
-RxDescriptors
-Valid Range: 8-1024
-Default Value: 64
-   This parameter defines the number of receive descriptors allocated by 
-   the driver. Increasing this value allows the driver to buffer more 
-   incoming packets before the driver is required to service an interrupt. 
-   The maximum value for Itanium-based systems is 64.
-
-TxDescriptors
-Valid Range: 19-1024
-Default Value: 64
-   This value is the number of transmit descriptors allocated by the driver. 
-   Increasing this value allows the protocol stack to queue more transmits at
-   the driver level. The maximum value for Itanium-based systems is 64.
-
-ucode
-Valid Range: 0-1 (0=off, 1=on)
-Default Value: 0 for 82558-based adapters
-               1 for 82559, 82550, and 82551-based adapters
-   On uploads the micro code to the adapter, which enables CPU Cycle Saver. 
-   See the section "CPU Cycle Saver" below.
-   Example usage: insmod e100.o ucode=1
-
-   Not available on 82557-based adapters.
-
-XsumRX
-Valid Range: 0-1 (0=off, 1=on)
-Default Value: 1
-   On allows Rx checksum offloading for TCP/UDP packets. Requires that the 
-   hardware support this feature.
-
-   Not available on 82557 and 82558-based adapters.
-
-
-CPU Cycle Saver
-================
-
-CPU Cycle Saver reduces CPU utilization by reducing the number of interrupts 
-that the adapter generates.
-
-When CPU Cycle Saver is turned off, the adapter generates one interrupt for 
-every frame that is received. This means that the operating system stops what
-it is doing and switches to the network driver in order to process the 
-receive.
-
-When CPU Cycle Saver is on, the adapter does not generate an interrupt for 
-every frame it receives. Instead, it waits until it receives several frames 
-before generating an interrupt. This reduces the amount of time spent 
-switching to and from the driver. 
-
-CPU Cycle Saver consists of these arguments: IntDelay, BundleMax and 
-BundleSmallFr. When IntDelay is increased, the adapter waits longer for 
-frames to arrive before generating the interrupt. By increasing BundleMax, 
-the network adapter waits for the number of small frames (less than 128 bytes)
-specified to arrive before generating the interrupt. When BundleSmallFr is 
-disabled, the adapter does not bundle small packets. Such small packets are 
-often, but not always, control packets that are better served immediately;
-therefore, BundleSmallFr is disabled by default.
-
-For most users, it is recommended that CPU Cycle Saver be used with the 
-default values specified in the Command Line Parameters section. However, in 
-some cases, performance problems may occur with CPU Cycle Saver. If such 
-problems are observed, we recommend turning off this feature by setting 
-ucode=0.
 
 
 Support
diff -Nru a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/networking/netconsole.txt	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/networking/packet_mmap.txt	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,412 @@
+
+DaveM:
+
+If you agree with it I will send two small patches to modify
+kernel's configure help. 
+
+	Ulisses
+
+--------------------------------------------------------------------------------
++ ABSTRACT
+--------------------------------------------------------------------------------
+
+This file documents the CONFIG_PACKET_MMAP option available with the PACKET
+socket interface on 2.4 and 2.6 kernels. This type of sockets is used for 
+capture network traffic with utilities like tcpdump or any other that uses 
+the libpcap library. 
+
+You can find the latest version of this document at
+
+    http://pusa.uv.es/~ulisses/packet_mmap/
+
+Please send me your comments to
+
+    Ulisses Alonso Camaró <uaca@i.hate.spam.alumni.uv.es>
+
+-------------------------------------------------------------------------------
++ Why use PACKET_MMAP
+--------------------------------------------------------------------------------
+
+In Linux 2.4/2.6 if PACKET_MMAP is not enabled, the capture process is very
+inefficient. It uses very limited buffers and requires one system call
+to capture each packet, it requires two if you want to get packet's 
+timestamp (like libpcap always does).
+
+In the other hand PACKET_MMAP is very efficient. PACKET_MMAP provides a size 
+configurable circular buffer mapped in user space. This way reading packets just 
+needs to wait for them, most of the time there is no need to issue a single 
+system call. By using a shared buffer between the kernel and the user 
+also has the benefit of minimizing packet copies.
+
+It's fine to use PACKET_MMAP to improve the performance of the capture process, 
+but it isn't everything. At least, if you are capturing at high speeds (this 
+is relative to the cpu speed), you should check if the device driver of your 
+network interface card supports some sort of interrupt load mitigation or 
+(even better) if it supports NAPI, also make sure it is enabled.
+
+--------------------------------------------------------------------------------
++ How to use CONFIG_PACKET_MMAP
+--------------------------------------------------------------------------------
+
+From the user standpoint, you should use the higher level libpcap library, wich
+is a de facto standard, portable across nearly all operating systems
+including Win32. 
+
+Said that, at time of this writing, official libpcap 0.8.1 is out and doesn't include
+support for PACKET_MMAP, and also probably the libpcap included in your distribution. 
+
+I'm aware of two implementations of PACKET_MMAP in libpcap:
+
+    http://pusa.uv.es/~ulisses/packet_mmap/  (by Simon Patarin, based on libpcap 0.6.2)
+    http://public.lanl.gov/cpw/              (by Phil Wood, based on lastest libpcap)
+
+The rest of this document is intended for people who want to understand
+the low level details or want to improve libpcap by including PACKET_MMAP
+support.
+
+--------------------------------------------------------------------------------
++ How to use CONFIG_PACKET_MMAP directly
+--------------------------------------------------------------------------------
+
+From the system calls stand point, the use of PACKET_MMAP involves
+the following process:
+
+
+[setup]     socket() -------> creation of the capture socket
+            setsockopt() ---> allocation of the circular buffer (ring)
+            mmap() ---------> maping of the allocated buffer to the
+                              user process
+
+[capture]   poll() ---------> to wait for incoming packets
+
+[shutdown]  close() --------> destruction of the capture socket and
+                              deallocation of all associated 
+                              resources.
+
+
+socket creation and destruction is straight forward, and is done 
+the same way with or without PACKET_MMAP:
+
+int fd;
+
+fd= socket(PF_PACKET, mode, htons(ETH_P_ALL))
+
+where mode is SOCK_RAW for the raw interface were link level
+information can be captured or SOCK_DGRAM for the cooked
+interface where link level information capture is not 
+supported and a link level pseudo-header is provided 
+by the kernel.
+
+The destruction of the socket and all associated resources
+is done by a simple call to close(fd).
+
+Next I will describe PACKET_MMAP settings and it's constraints,
+also the maping of the circular buffer in the user process and 
+the use of this buffer.
+
+--------------------------------------------------------------------------------
++ PACKET_MMAP settings
+--------------------------------------------------------------------------------
+
+
+To setup PACKET_MMAP from user level code is done with a call like
+
+     setsockopt(fd, SOL_PACKET, PACKET_RX_RING, (void *) &req, sizeof(req))
+
+The most significant argument in the previous call is the req parameter, 
+this parameter must to have the following structure:
+
+    struct tpacket_req
+    {
+        unsigned int    tp_block_size;  /* Minimal size of contiguous block */
+        unsigned int    tp_block_nr;    /* Number of blocks */
+        unsigned int    tp_frame_size;  /* Size of frame */
+        unsigned int    tp_frame_nr;    /* Total number of frames */
+    };
+
+This structure is defined in /usr/include/linux/if_packet.h and establishes a 
+circular buffer (ring) of unswappable memory mapped in the capture process. 
+Being mapped in the capture process allows reading the captured frames and 
+related meta-information like timestamps without requiring a system call.
+
+Captured frames are grouped in blocks. Each block is a physically contiguous 
+region of memory and holds tp_block_size/tp_frame_size frames. The total number 
+of blocks is tp_block_nr. Note that tp_frame_nr is a redundant parameter because
+
+    frames_per_block = tp_block_size/tp_frame_size
+
+indeed, packet_set_ring checks that the following condition is true
+
+    frames_per_block * tp_block_nr == tp_frame_nr
+
+
+Lets see an example, with the following values:
+
+     tp_block_size= 4096
+     tp_frame_size= 2048
+     tp_block_nr  = 4
+     tp_frame_nr  = 8
+
+we will get the following buffer structure:
+
+        block #1                 block #2         
++---------+---------+    +---------+---------+    
+| frame 1 | frame 2 |    | frame 3 | frame 4 |    
++---------+---------+    +---------+---------+    
+
+        block #3                 block #4
++---------+---------+    +---------+---------+
+| frame 5 | frame 6 |    | frame 7 | frame 8 |
++---------+---------+    +---------+---------+
+
+A frame can be of any size with the only condition it can fit in a block. A block
+can only hold an integer number of frames, or in other words, a frame cannot 
+be spawn accross two blocks so there are some datails you have to take into 
+account when choosing the frame_size. See "Maping and use of the circular 
+buffer (ring)".
+
+
+--------------------------------------------------------------------------------
++ PACKET_MMAP setting constraints
+--------------------------------------------------------------------------------
+
+In kernel versions prior to 2.4.26 (for the 2.4 branch) and 2.6.5 (2.6 branch),
+the PACKET_MMAP buffer could hold only 32768 frames in a 32 bit architecture or
+16384 in a 64 bit architecture. For information on these kernel versions
+see http://pusa.uv.es/~ulisses/packet_mmap/packet_mmap.pre-2.4.26_2.6.5.txt
+
+ Block size limit
+------------------
+
+As stated earlier, each block is a contiguous physical region of memory. These 
+memory regions are allocated with calls to the __get_free_pages() function. As 
+the name indicates, this function allocates pages of memory, and the second
+argument is "order" or a power of two number of pages, that is 
+(for PAGE_SIZE == 4096) order=0 ==> 4096 bytes, order=1 ==> 8192 bytes, 
+order=2 ==> 16384 bytes, etc. The maximum size of a 
+region allocated by __get_free_pages is determined by the MAX_ORDER macro. More 
+precisely the limit can be calculated as:
+
+   PAGE_SIZE << MAX_ORDER
+
+   In a i386 architecture PAGE_SIZE is 4096 bytes 
+   In a 2.4/i386 kernel MAX_ORDER is 10
+   In a 2.6/i386 kernel MAX_ORDER is 11
+
+So get_free_pages can allocate as much as 4MB or 8MB in a 2.4/2.6 kernel 
+respectively, with an i386 architecture.
+
+User space programs can include /usr/include/sys/user.h and 
+/usr/include/linux/mmzone.h to get PAGE_SIZE MAX_ORDER declarations.
+
+The pagesize can also be determined dynamically with the getpagesize (2) 
+system call. 
+
+
+ Block number limit
+--------------------
+
+To understand the constraints of PACKET_MMAP, we have to see the structure 
+used to hold the pointers to each block.
+
+Currently, this structure is a dynamically allocated vector with kmalloc 
+called pg_vec, its size limits the number of blocks that can be allocated.
+
+    +---+---+---+---+
+    | x | x | x | x |
+    +---+---+---+---+
+      |   |   |   |
+      |   |   |   v
+      |   |   v  block #4
+      |   v  block #3
+      v  block #2
+     block #1
+
+
+kmalloc allocates any number of bytes of phisically contiguous memory from 
+a pool of pre-determined sizes. This pool of memory is mantained by the slab 
+allocator wich is at the end the responsible for doing the allocation and 
+hence wich imposes the maximum memory that kmalloc can allocate. 
+
+In a 2.4/2.6 kernel and the i386 architecture, the limit is 131072 bytes. The 
+predetermined sizes that kmalloc uses can be checked in the "size-<bytes>" 
+entries of /proc/slabinfo
+
+In a 32 bit architecture, pointers are 4 bytes long, so the total number of 
+pointers to blocks is
+
+     131072/4 = 32768 blocks
+
+
+ PACKET_MMAP buffer size calculator
+------------------------------------
+
+Definitions:
+
+<size-max>    : is the maximum size of allocable with kmalloc (see /proc/slabinfo)
+<pointer size>: depends on the architecture -- sizeof(void *)
+<page size>   : depends on the architecture -- PAGE_SIZE or getpagesize (2)
+<max-order>   : is the value defined with MAX_ORDER
+<frame size>  : it's an upper bound of frame's capture size (more on this later)
+
+from these definitions we will derive 
+
+	<block number> = <size-max>/<pointer size>
+	<block size> = <pagesize> << <max-order>
+
+so, the max buffer size is
+
+	<block number> * <block size>
+
+and, the number of frames be
+
+	<block number> * <block size> / <frame size>
+
+Suposse the following parameters, wich apply for 2.6 kernel and an
+i386 architecture:
+
+	<size-max> = 131072 bytes
+	<pointer size> = 4 bytes
+	<pagesize> = 4096 bytes
+	<max-order> = 11
+
+and a value for <frame size> of 2048 byteas. These parameters will yield
+
+	<block number> = 131072/4 = 32768 blocks
+	<block size> = 4096 << 11 = 8 MiB.
+
+and hence the buffer will have a 262144 MiB size. So it can hold 
+262144 MiB / 2048 bytes = 134217728 frames
+
+
+Actually, this buffer size is not possible with an i386 architecture. 
+Remember that the memory is allocated in kernel space, in the case of 
+an i386 kernel's memory size is limited to 1GiB.
+
+All memory allocations are not freed until the socket is closed. The memory 
+allocations are done with GFP_KERNEL priority, this basically means that 
+the allocation can wait and swap other process' memory in order to allocate 
+the nececessary memory, so normally limits can be reached.
+
+ Other constraints
+-------------------
+
+If you check the source code you will see that what I draw here as a frame
+is not only the link level frame. At the begining of each frame there is a 
+header called struct tpacket_hdr used in PACKET_MMAP to hold link level's frame
+meta information like timestamp. So what we draw here a frame it's really 
+the following (from include/linux/if_packet.h):
+
+/*
+   Frame structure:
+
+   - Start. Frame must be aligned to TPACKET_ALIGNMENT=16
+   - struct tpacket_hdr
+   - pad to TPACKET_ALIGNMENT=16
+   - struct sockaddr_ll
+   - Gap, chosen so that packet data (Start+tp_net) alignes to 
+     TPACKET_ALIGNMENT=16
+   - Start+tp_mac: [ Optional MAC header ]
+   - Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16.
+   - Pad to align to TPACKET_ALIGNMENT=16
+ */
+           
+ 
+ The following are conditions that are checked in packet_set_ring
+
+   tp_block_size must be a multiple of PAGE_SIZE (1)
+   tp_frame_size must be greater than TPACKET_HDRLEN (obvious)
+   tp_frame_size must be a multiple of TPACKET_ALIGNMENT
+   tp_frame_nr   must be exactly frames_per_block*tp_block_nr
+
+Note that tp_block_size should be choosed to be a power of two or there will
+be a waste of memory.
+
+--------------------------------------------------------------------------------
++ Maping and use of the circular buffer (ring)
+--------------------------------------------------------------------------------
+
+The maping of the buffer in the user process is done with the conventional 
+mmap function. Even the circular buffer is compound of several physically
+discontiguous blocks of memory, they are contiguous to the user space, hence
+just one call to mmap is needed:
+
+    mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+
+If tp_frame_size is a divisor of tp_block_size frames will be 
+contiguosly spaced by tp_frame_size bytes. If not, each 
+tp_block_size/tp_frame_size frames there will be a gap between 
+the frames. This is because a frame cannot be spawn across two
+blocks. 
+
+At the beginning of each frame there is an status field (see 
+struct tpacket_hdr). If this field is 0 means that the frame is ready
+to be used for the kernel, If not, there is a frame the user can read 
+and the following flags apply:
+
+     from include/linux/if_packet.h
+
+     #define TP_STATUS_COPY          2 
+     #define TP_STATUS_LOSING        4 
+     #define TP_STATUS_CSUMNOTREADY  8 
+
+
+TP_STATUS_COPY        : This flag indicates that the frame (and associated
+                        meta information) has been truncated because it's 
+                        larger than tp_frame_size. This packet can be 
+                        read entirely with recvfrom().
+                        
+                        In order to make this work it must to be
+                        enabled previously with setsockopt() and 
+                        the PACKET_COPY_THRESH option. 
+
+                        The number of frames than can be buffered to 
+                        be read with recvfrom is limited like a normal socket.
+                        See the SO_RCVBUF option in the socket (7) man page.
+
+TP_STATUS_LOSING      : indicates there were packet drops from last time 
+                        statistics where checked with getsockopt() and
+                        the PACKET_STATISTICS option.
+
+TP_STATUS_CSUMNOTREADY: currently it's used for outgoing IP packets wich 
+                        it's checksum will be done in hardware. So while 
+                        reading the packet we should not try to check the 
+                        checksum. 
+
+for convenience there are also the following defines:
+
+     #define TP_STATUS_KERNEL        0
+     #define TP_STATUS_USER          1
+
+The kernel initializes all frames to TP_STATUS_KERNEL, when the kernel
+receives a packet it puts in the buffer and updates the status with
+at least the TP_STATUS_USER flag. Then the user can read the packet,
+once the packet is read the user must zero the status field, so the kernel 
+can use again that frame buffer.
+
+The user can use poll (any other variant should apply too) to check if new
+packets are in the ring:
+
+    struct pollfd pfd;
+
+    pfd.fd = fd;
+    pfd.revents = 0;
+    pfd.events = POLLIN|POLLRDNORM|POLLERR;
+
+    if (status == TP_STATUS_KERNEL)
+        retval = poll(&pfd, 1, timeout);
+
+It doesn't incur in a race condition to first check the status value and 
+then poll for frames.
+
+--------------------------------------------------------------------------------
++ THANKS
+--------------------------------------------------------------------------------
+   
+   Jesse Brandeburg, for fixing my grammathical/spelling errors
+
+>>> EOF
+-
+To unsubscribe from this list: send the line "unsubscribe linux-net" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
\ No newline at end of file
diff -Nru a/Documentation/power/tricks.txt b/Documentation/power/tricks.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/power/tricks.txt	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/Documentation/s390/driver-model.txt b/Documentation/s390/driver-model.txt
--- a/Documentation/s390/driver-model.txt	Sat Apr  3 19:38:40 2004
+++ b/Documentation/s390/driver-model.txt	Sat Apr  3 19:38:40 2004
@@ -250,7 +250,7 @@
 -----------
 
 The netiucv driver creates an attribute 'connection' under
-bus/iucv/drivers/NETIUCV. Piping to this attibute creates a new netiucv
+bus/iucv/drivers/netiucv. Piping to this attibute creates a new netiucv
 connection to the specified host.
 
 Netiucv connections show up under devices/iucv/ as "netiucv<ifnum>". The interface
diff -Nru a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
--- a/Documentation/scsi/st.txt	Sat Apr  3 19:38:41 2004
+++ b/Documentation/scsi/st.txt	Sat Apr  3 19:38:41 2004
@@ -2,7 +2,7 @@
 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 @@
 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 @@
 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 @@
 
 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 @@
 '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 -Nru a/Documentation/scsi/sym53c8xx_2.txt b/Documentation/scsi/sym53c8xx_2.txt
--- a/Documentation/scsi/sym53c8xx_2.txt	Sat Apr  3 19:38:41 2004
+++ b/Documentation/scsi/sym53c8xx_2.txt	Sat Apr  3 19:38:41 2004
@@ -567,7 +567,7 @@
         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 @@
 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 -Nru a/Documentation/sh/new-machine.txt b/Documentation/sh/new-machine.txt
--- a/Documentation/sh/new-machine.txt	Sat Apr  3 19:38:45 2004
+++ b/Documentation/sh/new-machine.txt	Sat Apr  3 19:38:45 2004
@@ -288,22 +288,22 @@
 used on it.
 
 Also, as soon as you have copied over a sample .config for your new board
-(assume arch/sh/configs/defconfig-vapor), you can also use this directly as a
+(assume arch/sh/configs/vapor_defconfig), you can also use this directly as a
 build target, and it will be implicitly listed as such in the help text.
 
 Looking at the 'make help' output, you should now see something like:
 
 Architecture specific targets (sh):
   zImage                  - Compressed kernel image (arch/sh/boot/zImage)
-  defconfig-adx           - Build for adx
-  defconfig-cqreek        - Build for cqreek
-  defconfig-dreamcast     - Build for dreamcast
+  adx_defconfig           - Build for adx
+  cqreek_defconfig        - Build for cqreek
+  dreamcast_defconfig     - Build for dreamcast
 ...
-  defconfig-vapor         - Build for vapor
+  vapor_defconfig         - Build for vapor
 
 which then allows you to do:
 
-$ make ARCH=sh CROSS_COMPILE=sh4-linux- defconfig-vapor vmlinux
+$ make ARCH=sh CROSS_COMPILE=sh4-linux- vapor_defconfig vmlinux
 
 which will in turn copy the defconfig for this board, run it through
 oldconfig (prompting you for any new options since the time of creation),
diff -Nru a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
--- a/Documentation/sound/alsa/ALSA-Configuration.txt	Sat Apr  3 19:38:41 2004
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt	Sat Apr  3 19:38:41 2004
@@ -112,7 +112,8 @@
 		- 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 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
   ------------------
 
@@ -574,6 +611,8 @@
                         * Digigram VX442
 
     omni	- Omni I/O support for MidiMan M-Audio Delta44/66
+    cs8427_timeout - reset timeout for the CS8427 chip (S/PDIF transciever)
+                     in msec resolution, default value is 500 (0.5 sec)
 
     Module supports up to 8 cards and autoprobe. Note: The consumer part
     is not used with all Envy24 based cards (for example in the MidiMan Delta
@@ -608,6 +647,7 @@
                      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 +667,15 @@
 
     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 +741,15 @@
 
     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
   -----------------
 
@@ -699,8 +757,10 @@
 
     port	- port number or -1 (disable)
     irq		- IRQ number or -1 (disable)
+    acpipnp	- ACPI PnP detection - 0 = disable, 1 = enable (default)
 
-    Module supports multiple devices (max 8).
+    Module supports multiple devices (max 8) and ACPI PnP.  If PnP is not
+    used (or ACPI not enabled), port and irq must be specified.
     
   Module snd-mtpav
   ----------------
@@ -1169,6 +1229,16 @@
     Module supports autoprobe and multiple chips (max 8).
 
     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 -Nru a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl
--- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl	Sat Apr  3 19:38:41 2004
+++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	Sat Apr  3 19:38:42 2004
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl	Sat Apr  3 19:38:42 2004
@@ -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 @@
             <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 @@
         <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 @@
       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 @@
 
       <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 @@
     </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 @@
 	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 @@
 
 	<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 @@
       <informalexample>
         <programlisting>
 <![CDATA[
-  extra-subdir-y := pdplus vx222 xyz
+  obj-$(CONFIG_SND) += xyz/
 ]]>
         </programlisting>
       </informalexample>
@@ -5739,13 +5750,13 @@
 	<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,28 +5770,11 @@
 
 	<listitem>
 	<para>
-	Modify alsa-driver/acore/Makefile
+	Create the Kconfig entry
 	</para>
 
 	<para>
 	This procedure is as same as in the last section.
-	</para>
-	</listitem>
-
-	<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>
 
diff -Nru a/Documentation/sound/alsa/Joystick.txt b/Documentation/sound/alsa/Joystick.txt
--- a/Documentation/sound/alsa/Joystick.txt	Sat Apr  3 19:38:43 2004
+++ b/Documentation/sound/alsa/Joystick.txt	Sat Apr  3 19:38:43 2004
@@ -43,7 +43,8 @@
     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 -Nru a/Documentation/sound/alsa/MIXART.txt b/Documentation/sound/alsa/MIXART.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/sound/alsa/MIXART.txt	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/sound/alsa/Procfile.txt	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,185 @@
+		Proc Files of ALSA Drivers
+		==========================
+		Takashi Iwai <tiwai@suse.de>
+
+General
+-------
+
+ALSA has its own proc tree, /proc/asound.  Many useful information are
+found in this tree.  When you encounter a problem and need debugging,
+check the files listed in the following sections.
+
+Each card has its subtree cardX, where X is from 0 to 7. The
+card-specific files are stored in the card* subdirectories.
+
+
+Global Information
+------------------
+
+cards
+	Shows the list of currently configured ALSA drivers,
+	index, the id string, short and long descriptions.
+
+version
+	Shows the version string and compile date.
+
+modules
+	Lists the module of each card
+
+devices
+	Lists the ALSA native device mappings.
+
+meminfo
+	Shows the status of allocated pages via ALSA drivers.
+	Appears only when CONFIG_SND_DEBUG=y.
+
+hwdep
+	Lists the currently available hwdep devices in format of
+	<card>-<device>: <name>
+
+pcm
+	Lists the currently available PCM devices in format of
+	<card>-<device>: <id>: <name> : <sub-streams>
+
+timer
+	Lists the currently available timer devices
+
+
+oss/devices
+	Lists the OSS device mappings.
+
+oss/sndstat
+	Provides the output compatible with /dev/sndstat.
+	You can symlink this to /dev/sndstat.
+
+
+Card Specific Files
+-------------------
+
+The card-specific files are found in /proc/asound/card* directories.
+Some drivers (e.g. cmipci) have their own proc entries for the
+register dump, etc (e.g. /proc/asound/card*/cmipci shows the register
+dump).  These files would be really helpful for debugging.
+
+When PCM devices are available on this card, you can see directories
+like pcm0p or pcm1c.  They hold the PCM information for each PCM
+stream.  The number after 'pcm' is the PCM device number from 0, and
+the last 'p' or 'c' means playback or capture direction.  The files in
+this subtree is described later.
+
+The status of MIDI I/O is found in midi* files.  It shows the device
+name and the received/transmitted bytes through the MIDI device.
+
+When the card is equipped with AC97 codecs, there are codec97#*
+subdirectories (desribed later).
+
+When the OSS mixer emulation is enabled (and the module is loaded),
+oss_mixer file appears here, too.  This shows the current mapping of
+OSS mixer elements to the ALSA control elements.  You can change the
+mapping by writing to this device.  Read OSS-Emulation.txt for
+details.
+
+
+PCM Proc Files
+--------------
+
+card*/pcm*/info
+	The general information of this PCM device: card #, device #,
+	substreams, etc.
+
+card*/pcm*/xrun_debug
+	This file appears when CONFIG_SND_DEBUG=y.
+	This shows the status of xrun (= buffer overrun/xrun) debug of
+	ALSA PCM middle layer, as an integer from 0 to 2.  The value
+	can be changed by writing to this file, such as
+
+		 # cat 2 > /proc/asound/card0/pcm0p/xrun_debug
+
+	When this value is greater than 0, the driver will show the
+	messages to kernel log when an xrun is detected.  The debug
+	message is shown also when the invalid H/W pointer is detected
+	at the update of periods (usually called from the interrupt
+	handler).
+
+	When this value is greater than 1, the driver will show the
+	stack trace additionally.  This may help the debugging.
+
+card*/pcm*/sub*/info
+	The general information of this PCM sub-stream.
+
+card*/pcm*/sub*/status
+	The current status of this PCM sub-stream, elapsed time,
+	H/W position, etc.
+
+card*/pcm*/sub*/hw_params
+	The hardware parameters set for this sub-stream.
+
+card*/pcm*/sub*/sw_params
+	The soft parameters set for this sub-stream.
+
+card*/pcm*/sub*/prealloc
+	The buffer pre-allocation information.
+
+
+AC97 Codec Information
+----------------------
+
+card*/codec97#*/ac97#?-?
+	Shows the general information of this AC97 codec chip, such as
+	name, capabilities, set up.
+
+card*/codec97#0/ac97#?-?+regs
+	Shows the AC97 register dump.  Useful for debugging.
+
+
+Sequencer Information
+---------------------
+
+seq/drivers
+	Lists the currently available ALSA sequencer drivers.
+
+seq/clients
+	Shows the list of currently available sequencer clinets and
+	ports.  The connection status and the running status are shown
+	in this file, too.
+
+seq/queues
+	Lists the currently allocated/running sequener queues.
+
+seq/timer
+	Lists the currently allocated/running sequencer timers.
+
+seq/oss
+	Lists the OSS-compatible sequencer stuffs.
+
+
+Help For Debugging?
+-------------------
+
+When the problem is related with PCM, first try to turn on xrun_debug
+mode.  This will give you the kernel messages when and where xrun
+happened.
+
+If it's really a bug, report it with the following information
+
+  - the name of the driver/card, show in /proc/asound/cards
+  - the reigster dump, if available (e.g. card*/cmipci)
+
+when it's a PCM problem,
+
+  - set-up of PCM, shown in hw_parms, sw_params, and status in the PCM
+    sub-stream directory
+
+when it's a mixer problem,
+
+  - AC97 proc files, codec97#*/* files
+
+for USB audio/midi,
+
+  - output of lsusb -v
+  - stream* files in card directory
+
+
+The ALSA bug-tracking system is found at:
+
+    https://bugtrack.alsa-project.org/alsa-bug/
diff -Nru a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
--- a/Documentation/sysctl/vm.txt	Sat Apr  3 19:38:54 2004
+++ b/Documentation/sysctl/vm.txt	Sat Apr  3 19:38:54 2004
@@ -22,6 +22,7 @@
 - dirty_background_ratio
 - dirty_expire_centisecs
 - dirty_writeback_centisecs
+- max_map_count
 - min_free_kbytes
 
 ==============================================================
@@ -74,6 +75,21 @@
 The number of pages the kernel reads in at once is equal to
 2 ^ page-cluster. Values above 2 ^ 5 don't make much sense
 for swap because we only cluster swap data in 32-page groups.
+
+==============================================================
+
+max_map_count:
+
+This file contains the maximum number of memory map areas a process
+may have. Memory map areas are used as a side-effect of calling
+malloc, directly by mmap and mprotect, and also when loading shared
+libraries.
+
+While most applications need less than a thousand maps, certain
+programs, particularly malloc debuggers, may consume lots of them,
+e.g., up to one or two maps per allocation.
+
+The default value is 65536.
 
 ==============================================================
 
diff -Nru a/Documentation/usb/acm.txt b/Documentation/usb/acm.txt
--- a/Documentation/usb/acm.txt	Sat Apr  3 19:38:42 2004
+++ b/Documentation/usb/acm.txt	Sat Apr  3 19:38:42 2004
@@ -28,7 +28,7 @@
 
 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 @@
 
   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 -Nru a/Documentation/usb/brlvger.txt b/Documentation/usb/brlvger.txt
--- a/Documentation/usb/brlvger.txt	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt
--- a/Documentation/usb/error-codes.txt	Sat Apr  3 19:38:40 2004
+++ b/Documentation/usb/error-codes.txt	Sat Apr  3 19:38:40 2004
@@ -70,7 +70,9 @@
 			(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 -Nru a/Documentation/usb/mtouchusb.txt b/Documentation/usb/mtouchusb.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/usb/mtouchusb.txt	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/Documentation/usb/scanner.txt b/Documentation/usb/scanner.txt
--- a/Documentation/usb/scanner.txt	Sat Apr  3 19:38:56 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
--- a/Documentation/x86_64/boot-options.txt	Sat Apr  3 19:38:56 2004
+++ b/Documentation/x86_64/boot-options.txt	Sat Apr  3 19:38:56 2004
@@ -136,7 +136,7 @@
 
 IOMMU
 
-  iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]]
+  iommu=[size][,noagp][,off][,force][,noforce][,leak][,memaper[=order]][,soft]
    size  set size of iommu (in bytes)
    noagp don't initialize the AGP driver and use full aperture.
    off   don't use the IOMMU
@@ -144,5 +144,9 @@
    memaper[=order] allocate an own aperture over RAM with size 32MB^order.
    noforce don't force IOMMU usage. Default.
    force  Force IOMMU
+   soft   Use software bounce buffering for non 32bit IO. Default on Intel
+          machines. 
 
+  swiotlb=pages
 
+  Prereserve that many 4K pages for the software IO bounce buffering.
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Sat Apr  3 19:38:44 2004
+++ b/MAINTAINERS	Sat Apr  3 19:38:44 2004
@@ -201,7 +201,7 @@
 AGPGART DRIVER
 P:	Dave Jones
 M:	davej@codemonkey.org.uk
-W:	http://www.codemonkey.org.uk/agp/
+W:	http://www.codemonkey.org.uk/projects/agp/
 S:	Maintained
 
 AHA152X SCSI DRIVER
@@ -1966,13 +1966,6 @@
 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 +2030,6 @@
 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
@@ -2152,14 +2143,6 @@
 L:	linux-usb-users@lists.sourceforge.net
 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
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Sat Apr  3 19:38:45 2004
+++ b/Makefile	Sat Apr  3 19:38:45 2004
@@ -1,8 +1,8 @@
 VERSION = 2
 PATCHLEVEL = 6
-SUBLEVEL = 4
+SUBLEVEL = 5
 EXTRAVERSION =
-NAME=Feisty Dunnart
+NAME=Zonked Quokka
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -107,6 +107,16 @@
 # We process the rest of the Makefile if this is the final invocation of make
 ifeq ($(skip-makefile),)
 
+# Make sure we're not wasting cpu-cycles doing locale handling, yet do make
+# sure error messages appear in the user-desired language
+ifdef LC_ALL
+LANG := $(LC_ALL)
+LC_ALL :=
+endif
+LC_COLLATE := C
+LC_CTYPE := C
+export LANG LC_ALL LC_COLLATE LC_CTYPE
+
 srctree		:= $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
 TOPDIR		:= $(srctree)
 # FIXME - TOPDIR is obsolete, use srctree/objtree
@@ -304,17 +314,10 @@
 # ===========================================================================
 # 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 +361,9 @@
 # *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 +371,16 @@
 # 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 +413,9 @@
 # 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
@@ -558,7 +573,7 @@
 # 	Handle descending into subdirectories listed in $(SUBDIRS)
 
 .PHONY: $(SUBDIRS)
-$(SUBDIRS): prepare-all
+$(SUBDIRS): prepare-all scripts
 	$(Q)$(MAKE) $(build)=$@
 
 # Things we need to do before we recursively start building the kernel
@@ -633,9 +648,9 @@
 
 # 	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
@@ -647,7 +662,7 @@
 uts_len := 64
 
 define filechk_version.h
-	if expr length "$(KERNELRELEASE)" \> $(uts_len) >/dev/null ; then \
+	if ((`echo -n "$(KERNELRELEASE)" | wc -c ` > $(uts_len))); then \
 	  echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \
 	  exit 1; \
 	fi; \
@@ -757,26 +772,15 @@
 #                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 +789,36 @@
 $(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
 # ---------------------------------------------------------------------------
@@ -909,6 +921,7 @@
 	@echo  '  dir/file.[ois]  - Build specified target only'
 	@echo  '  rpm		  - Build a kernel as an RPM package'
 	@echo  '  tags/TAGS	  - Generate tags file for editors'
+	@echo  '  cscope	  - Generate cscope index'
 	@echo  ''
 	@echo  'Documentation targets:'
 	@$(MAKE) -f $(srctree)/Documentation/DocBook/Makefile dochelp
@@ -932,7 +945,7 @@
 
 # Documentation targets
 # ---------------------------------------------------------------------------
-%docs: scripts/docproc FORCE
+%docs: scripts FORCE
 	$(Q)$(MAKE) $(build)=Documentation/DocBook $@
 
 # Scripts to check various things for consistency
@@ -985,7 +998,7 @@
 	@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 -Nru a/arch/alpha/Kconfig b/arch/alpha/Kconfig
--- a/arch/alpha/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/arch/alpha/Kconfig	Sat Apr  3 19:38:54 2004
@@ -188,7 +188,7 @@
 	help
 	  The Digital PersonalWorkStation (PWS 433a, 433au, 500a, 500au, 600a,
 	  or 600au).  There is an Installation HOWTO for this hardware at
-	  <http://members.brabant.chello.nl/~s.vandereijk/miata.html>.
+	  <http://eijk.homelinux.org/~stefan/miata.html>.
 
 config ALPHA_MIKASA
 	bool "Mikasa"
@@ -486,19 +486,8 @@
 	  singleprocessor machines. On a singleprocessor machine, the kernel
 	  will run faster if you say N here.
 
-	  Note that if you say Y here and choose architecture "586" or
-	  "Pentium" under "Processor family", the kernel will not work on 486
-	  architectures. Similarly, multiprocessor kernels for the "PPro"
-	  architecture may not work on all Pentium based boards.
-
-	  People using multiprocessor machines who say Y here should also say
-	  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
-	  Management" code will be disabled if you say Y here.
-
-	  See also the <file:Documentation/smp.tex>,
-	  <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
-	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
-	  <http://www.tldp.org/docs.html#howto>.
+	  See also the <file:Documentation/smp.tex>, and the SMP-HOWTO
+	  available at <http://www.tldp.org/docs.html#howto>.
 
 	  If you don't know what to do here, say N.
 
diff -Nru a/arch/alpha/boot/misc.c b/arch/alpha/boot/misc.c
--- a/arch/alpha/boot/misc.c	Sat Apr  3 19:38:43 2004
+++ b/arch/alpha/boot/misc.c	Sat Apr  3 19:38:43 2004
@@ -25,7 +25,7 @@
 #define memzero(s,n)	memset ((s),0,(n))
 #define puts		srm_printk
 extern long srm_printk(const char *, ...)
-     __attribute__ ((format (printf, 1, 2)));;
+     __attribute__ ((format (printf, 1, 2)));
 
 /*
  * gzip delarations
diff -Nru a/arch/alpha/defconfig b/arch/alpha/defconfig
--- a/arch/alpha/defconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/alpha/defconfig	Sat Apr  3 19:38:43 2004
@@ -2,8 +2,8 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ALPHA=y
+CONFIG_64BIT=y
 CONFIG_MMU=y
-CONFIG_SWAP=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_ISA_DMA=y
 
@@ -11,14 +11,28 @@
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
 #
-CONFIG_NET=y
+CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+# 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
@@ -26,6 +40,8 @@
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 
 #
@@ -45,6 +61,8 @@
 # CONFIG_ALPHA_EIGER is not set
 # CONFIG_ALPHA_JENSEN is not set
 # CONFIG_ALPHA_LX164 is not set
+# CONFIG_ALPHA_LYNX is not set
+# CONFIG_ALPHA_MARVEL is not set
 # CONFIG_ALPHA_MIATA is not set
 # CONFIG_ALPHA_MIKASA is not set
 # CONFIG_ALPHA_NAUTILUS is not set
@@ -62,26 +80,35 @@
 # CONFIG_ALPHA_TITAN is not set
 # CONFIG_ALPHA_WILDFIRE is not set
 CONFIG_ISA=y
-CONFIG_EISA=y
 CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_ALPHA_CORE_AGP=y
 CONFIG_ALPHA_BROKEN_IRQ_MASK=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_EISA=y
 # CONFIG_SMP is not set
 # CONFIG_DISCONTIGMEM is not set
 CONFIG_VERBOSE_MCHECK=y
+CONFIG_VERBOSE_MCHECK_ON=1
+CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
+CONFIG_EISA_PCI_EISA=y
+CONFIG_EISA_VIRTUAL_ROOT=y
+CONFIG_EISA_NAMES=y
 CONFIG_SRM_ENV=m
-# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_AOUT is not set
 # CONFIG_BINFMT_EM86 is not set
+# CONFIG_BINFMT_MISC is not set
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -89,10 +116,14 @@
 # CONFIG_MTD is not set
 
 #
-# Plug and Play configuration
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
 #
 CONFIG_PNP=y
-# CONFIG_PNP_NAMES is not set
 # CONFIG_PNP_DEBUG is not set
 
 #
@@ -111,63 +142,60 @@
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
 # CONFIG_BLK_DEV_RAM is not set
 
 #
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
 # ATA/ATAPI/MFM/RLL support
 #
 CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
+CONFIG_IDE_MAX_HWIFS=4
 CONFIG_BLK_DEV_IDE=y
 
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
-# CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
 # 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_BLK_DEV_ISAPNP is not set
+CONFIG_IDE_GENERIC=y
+# CONFIG_BLK_DEV_IDEPNP is not set
 CONFIG_BLK_DEV_IDEPCI=y
-CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
-CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDE_TCQ is not set
 # 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=y
 # CONFIG_IDEDMA_ONLYDISK is not set
-CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_AEC62XX is not set
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_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=y
+# 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_OPTI621 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
@@ -176,13 +204,16 @@
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_VIA82CXXX is not set
 # CONFIG_IDE_CHIPSETS is not set
-CONFIG_IDEDMA_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
 
 #
 # SCSI support type (disk, tape, CD-ROM)
@@ -203,85 +234,104 @@
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS 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_AACRAID is not set
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 CONFIG_AIC7XXX_RESET_DELAY_MS=5000
+# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
 # CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
+# 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_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_DMA 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_INITIO is not set
+# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-CONFIG_SCSI_NCR53C8XX=y
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set
 # CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_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_DC395x 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 is not set
+
+#
 # Fusion MPT device support
 #
 # CONFIG_FUSION is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
 #
+# I2O device support
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
 # Networking options
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_NETLINK_DEV=y
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-# CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_NET_KEY=m
 CONFIG_INET=y
@@ -296,7 +346,17 @@
 # CONFIG_SYN_COOKIES is not set
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
-CONFIG_XFRM_USER=m
+# 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
@@ -304,14 +364,18 @@
 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=m
 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
@@ -321,15 +385,15 @@
 # CONFIG_IP_NF_MATCH_HELPER is not set
 # CONFIG_IP_NF_MATCH_STATE is not set
 # CONFIG_IP_NF_MATCH_CONNTRACK is not set
-# CONFIG_IP_NF_MATCH_UNCLEAN is not set
 # CONFIG_IP_NF_MATCH_OWNER is not set
 CONFIG_IP_NF_FILTER=m
 # CONFIG_IP_NF_TARGET_REJECT is not set
-# CONFIG_IP_NF_TARGET_MIRROR is not set
 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
@@ -340,7 +404,8 @@
 # CONFIG_IP_NF_TARGET_TCPMSS is not set
 # CONFIG_IP_NF_ARPTABLES is not set
 CONFIG_IP_NF_COMPAT_IPCHAINS=y
-# CONFIG_IPV6 is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
 
 #
 # SCTP Configuration (EXPERIMENTAL)
@@ -349,9 +414,9 @@
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 CONFIG_VLAN_8021Q=m
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE 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
@@ -369,10 +434,6 @@
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
-
-#
-# Network device support
-#
 CONFIG_NETDEVICES=y
 
 #
@@ -390,6 +451,7 @@
 # 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=y
@@ -400,6 +462,7 @@
 # CONFIG_EL3 is not set
 # CONFIG_3C515 is not set
 CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
@@ -412,6 +475,7 @@
 CONFIG_TULIP=y
 # 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
@@ -421,10 +485,12 @@
 # CONFIG_NET_ISA 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_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_CS89x0 is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
@@ -440,7 +506,6 @@
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_NET_POCKET is not set
 
@@ -448,13 +513,20 @@
 # Ethernet (1000 Mbit)
 #
 # CONFIG_ACENIC is not set
-CONFIG_DL2K=m
+# CONFIG_DL2K is not set
 # CONFIG_E1000 is not set
-CONFIG_NS83820=m
+# CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 CONFIG_YELLOWFIN=y
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 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_HIPPI is not set
 # CONFIG_PPP is not set
@@ -470,8 +542,8 @@
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # Wan interfaces
@@ -484,34 +556,74 @@
 # CONFIG_HAMRADIO is not set
 
 #
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Telephony Support
 #
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
 #
-# CONFIG_INPUT is not set
+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 is not set
+# CONFIG_INPUT_EVBUG is not set
 
 #
 # Input I/O drivers
 #
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
 
 #
 # Input Device Drivers
 #
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# 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_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Character devices
@@ -524,32 +636,30 @@
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_CORE=m
+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
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
 
 #
-# Mice
+# IPMI
 #
-# CONFIG_BUSMOUSE is not set
-# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
 CONFIG_RTC=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
@@ -564,72 +674,134 @@
 # 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 is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=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_QUOTA is not set
-CONFIG_AUTOFS_FS=m
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
 CONFIG_REISERFS_FS=m
 # CONFIG_REISERFS_CHECK is not set
 # CONFIG_REISERFS_PROC_INFO 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=m
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# 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_HUGETLB_PAGE is not set
+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_EXT3_FS is not set
-# CONFIG_JBD is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
-CONFIG_TMPFS=y
-CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_XFS_FS is not set
 
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=m
 CONFIG_NFS_V3=y
 # CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 CONFIG_NFSD=m
 CONFIG_NFSD_V3=y
 # CONFIG_NFSD_V4 is not set
 # CONFIG_NFSD_TCP is not set
-CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=m
-# CONFIG_CIFS is not set
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # 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
 
 #
@@ -638,11 +810,11 @@
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_OSF_PARTITION=y
 CONFIG_MSDOS_PARTITION=y
-CONFIG_NLS=y
 
 #
 # Native Language Support
 #
+CONFIG_NLS=y
 CONFIG_NLS_DEFAULT="iso8859-1"
 CONFIG_NLS_CODEPAGE_437=y
 # CONFIG_NLS_CODEPAGE_737 is not set
@@ -683,29 +855,9 @@
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Console drivers
-#
-CONFIG_VGA_CONSOLE=y
-
-#
-# Frame-buffer support
-#
-# CONFIG_FB is not set
-
+# Profiling support
 #
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_PROFILING is not set
 
 #
 # Kernel hacking
@@ -718,16 +870,34 @@
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_RWLOCK is not set
 # CONFIG_DEBUG_SEMAPHORE is not set
+CONFIG_DEBUG_INFO=y
 
 #
 # Security options
 #
-CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY is not set
 
 #
 # 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=m
+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 is not set
+# CONFIG_CRYPTO_TEST is not set
 
 #
 # Library routines
diff -Nru a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
--- a/arch/alpha/kernel/setup.c	Sat Apr  3 19:38:41 2004
+++ b/arch/alpha/kernel/setup.c	Sat Apr  3 19:38:41 2004
@@ -38,8 +38,9 @@
 #include <linux/sysrq.h>
 #include <linux/reboot.h>
 #endif
-
 #include <linux/notifier.h>
+#include <asm/io.h>
+
 extern struct notifier_block *panic_notifier_list;
 static int alpha_panic_event(struct notifier_block *, unsigned long, void *);
 static struct notifier_block alpha_panic_block = {
@@ -64,6 +65,11 @@
 struct hwrpb_struct *hwrpb;
 unsigned long srm_hae;
 
+int alpha_l1i_cacheshape;
+int alpha_l1d_cacheshape;
+int alpha_l2_cacheshape;
+int alpha_l3_cacheshape;
+
 #ifdef CONFIG_VERBOSE_MCHECK
 /* 0=minimum, 1=verbose, 2=all */
 /* These can be overridden via the command line, ie "verbose_mcheck=2") */
@@ -113,6 +119,7 @@
 static struct alpha_machine_vector *get_sysvec_byname(const char *);
 static void get_sysnames(unsigned long, unsigned long, unsigned long,
 			 char **, char **);
+static void determine_cpu_caches (unsigned int);
 
 static char command_line[COMMAND_LINE_SIZE];
 char saved_command_line[COMMAND_LINE_SIZE];
@@ -672,6 +679,9 @@
 	/* Find our memory.  */
 	setup_memory(kernel_end);
 
+	/* First guess at cpu cache sizes.  Do this before init_arch.  */
+	determine_cpu_caches(cpu->type);
+
 	/* Initialize the machine.  Usually has to do with setting up
 	   DMA windows and the like.  */
 	if (alpha_mv.init_arch)
@@ -1156,6 +1166,18 @@
 	return count;
 }
 
+static void
+show_cache_size (struct seq_file *f, const char *which, int shape)
+{
+	if (shape == -1)
+		seq_printf (f, "%s\t\t: n/a\n", which);
+	else if (shape == 0)
+		seq_printf (f, "%s\t\t: unknown\n", which);
+	else
+		seq_printf (f, "%s\t\t: %dK, %d-way, %db line\n",
+			    which, shape >> 10, shape & 15,
+			    1 << ((shape >> 4) & 15));
+}
 
 static int
 show_cpuinfo(struct seq_file *f, void *slot)
@@ -1229,9 +1251,202 @@
 		       num_online_cpus(), cpu_present_mask);
 #endif
 
+	show_cache_size (f, "L1 Icache", alpha_l1i_cacheshape);
+	show_cache_size (f, "L1 Dcache", alpha_l1d_cacheshape);
+	show_cache_size (f, "L2 cache", alpha_l2_cacheshape);
+	show_cache_size (f, "L3 cache", alpha_l3_cacheshape);
+
 	return 0;
 }
 
+static int __init
+read_mem_block(int *addr, int stride, int size)
+{
+	long nloads = size / stride, cnt, tmp;
+
+	__asm__ __volatile__(
+	"	rpcc    %0\n"
+	"1:	ldl	%3,0(%2)\n"
+	"	subq	%1,1,%1\n"
+	/* Next two XORs introduce an explicit data dependency between
+	   consecutive loads in the loop, which will give us true load
+	   latency. */
+	"	xor	%3,%2,%2\n"
+	"	xor	%3,%2,%2\n"
+	"	addq	%2,%4,%2\n"
+	"	bne	%1,1b\n"
+	"	rpcc	%3\n"
+	"	subl	%3,%0,%0\n"
+	: "=&r" (cnt), "=&r" (nloads), "=&r" (addr), "=&r" (tmp)
+	: "r" (stride), "1" (nloads), "2" (addr));
+
+	return cnt / (size / stride);
+}
+
+#define CSHAPE(totalsize, linesize, assoc) \
+  ((totalsize & ~0xff) | (linesize << 4) | assoc)
+
+/* ??? EV5 supports up to 64M, but did the systems with more than
+   16M of BCACHE ever exist? */
+#define MAX_BCACHE_SIZE	16*1024*1024
+
+/* Note that the offchip caches are direct mapped on all Alphas. */
+static int __init
+external_cache_probe(int minsize, int width)
+{
+	int cycles, prev_cycles = 1000000;
+	int stride = 1 << width;
+	long size = minsize, maxsize = MAX_BCACHE_SIZE * 2;
+
+	if (maxsize > (max_low_pfn + 1) << PAGE_SHIFT)
+		maxsize = 1 << (floor_log2(max_low_pfn + 1) + PAGE_SHIFT);
+
+	/* Get the first block cached. */
+	read_mem_block(__va(0), stride, size);
+
+	while (size < maxsize) {
+		/* Get an average load latency in cycles. */
+		cycles = read_mem_block(__va(0), stride, size);
+		if (cycles > prev_cycles * 2) {
+			/* Fine, we exceed the cache. */
+			printk("%ldK Bcache detected; load hit latency %d "
+			       "cycles, load miss latency %d cycles\n",
+			       size >> 11, prev_cycles, cycles);
+			return CSHAPE(size >> 1, width, 1);
+		}
+		/* Try to get the next block cached. */
+		read_mem_block(__va(size), stride, size);
+		prev_cycles = cycles;
+		size <<= 1;
+	}
+	return -1;	/* No BCACHE found. */
+}
+
+static void __init
+determine_cpu_caches (unsigned int cpu_type)
+{
+	int L1I, L1D, L2, L3;
+
+	switch (cpu_type) {
+	case EV4_CPU:
+	case EV45_CPU:
+	  {
+		if (cpu_type == EV4_CPU)
+			L1I = CSHAPE(8*1024, 5, 1);
+		else
+			L1I = CSHAPE(16*1024, 5, 1);
+		L1D = L1I;
+		L3 = -1;
+	
+		/* BIU_CTL is a write-only Abox register.  PALcode has a
+		   shadow copy, and may be available from some versions
+		   of the CSERVE PALcall.  If we can get it, then
+
+			unsigned long biu_ctl, size;
+			size = 128*1024 * (1 << ((biu_ctl >> 28) & 7));
+			L2 = CSHAPE (size, 5, 1);
+
+		   Unfortunately, we can't rely on that.
+		*/
+		L2 = external_cache_probe(128*1024, 5);
+		break;
+	  }
+
+	case LCA4_CPU:
+	  {
+		unsigned long car, size;
+
+		L1I = L1D = CSHAPE(8*1024, 5, 1);
+		L3 = -1;
+
+		car = *(vuip) phys_to_virt (0x120000078);
+		size = 64*1024 * (1 << ((car >> 5) & 7));
+		/* No typo -- 8 byte cacheline size.  Whodathunk.  */
+		L2 = (car & 1 ? CSHAPE (size, 3, 1) : -1);
+		break;
+	  }
+
+	case EV5_CPU:
+	case EV56_CPU:
+	  {
+		unsigned long sc_ctl, width;
+
+		L1I = L1D = CSHAPE(8*1024, 5, 1);
+
+		/* Check the line size of the Scache.  */
+		sc_ctl = *(vulp) phys_to_virt (0xfffff000a8);
+		width = sc_ctl & 0x1000 ? 6 : 5;
+		L2 = CSHAPE (96*1024, width, 3);
+
+		/* BC_CONTROL and BC_CONFIG are write-only IPRs.  PALcode
+		   has a shadow copy, and may be available from some versions
+		   of the CSERVE PALcall.  If we can get it, then
+
+			unsigned long bc_control, bc_config, size;
+			size = 1024*1024 * (1 << ((bc_config & 7) - 1));
+			L3 = (bc_control & 1 ? CSHAPE (size, width, 1) : -1);
+
+		   Unfortunately, we can't rely on that.
+		*/
+		L3 = external_cache_probe(1024*1024, width);
+		break;
+	  }
+
+	case PCA56_CPU:
+	case PCA57_CPU:
+	  {
+		unsigned long cbox_config, size;
+
+		if (cpu_type == PCA56_CPU) {
+			L1I = CSHAPE(16*1024, 6, 1);
+			L1D = CSHAPE(8*1024, 5, 1);
+		} else {
+			L1I = CSHAPE(32*1024, 6, 2);
+			L1D = CSHAPE(16*1024, 5, 1);
+		}
+		L3 = -1;
+
+		cbox_config = *(vulp) phys_to_virt (0xfffff00008);
+		size = 512*1024 * (1 << ((cbox_config >> 12) & 3));
+
+#if 0
+		L2 = ((cbox_config >> 31) & 1 ? CSHAPE (size, 6, 1) : -1);
+#else
+		L2 = external_cache_probe(512*1024, 6);
+#endif
+		break;
+	  }
+
+	case EV6_CPU:
+	case EV67_CPU:
+	case EV68CB_CPU:
+	case EV68AL_CPU:
+	case EV68CX_CPU:
+	case EV69_CPU:
+		L1I = L1D = CSHAPE(64*1024, 6, 2);
+		L2 = external_cache_probe(1024*1024, 6);
+		L3 = -1;
+		break;
+
+	case EV7_CPU:
+	case EV79_CPU:
+		L1I = L1D = CSHAPE(64*1024, 6, 2);
+		L2 = CSHAPE(7*1024*1024/4, 6, 7);
+		L3 = -1;
+		break;
+
+	default:
+		/* Nothing known about this cpu type.  */
+		L1I = L1D = L2 = L3 = 0;
+		break;
+	}
+
+	alpha_l1i_cacheshape = L1I;
+	alpha_l1d_cacheshape = L1D;
+	alpha_l2_cacheshape = L2;
+	alpha_l3_cacheshape = L3;
+}
+
 /*
  * We show only CPU #0 info.
  */
@@ -1260,9 +1475,8 @@
 };
 
 
-static int alpha_panic_event(struct notifier_block *this,
-			     unsigned long event,
-			     void *ptr)
+static int
+alpha_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
 #if 1
 	/* FIXME FIXME FIXME */
diff -Nru a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
--- a/arch/alpha/kernel/smp.c	Sat Apr  3 19:38:42 2004
+++ b/arch/alpha/kernel/smp.c	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
--- a/arch/alpha/kernel/sys_nautilus.c	Sat Apr  3 19:38:42 2004
+++ b/arch/alpha/kernel/sys_nautilus.c	Sat Apr  3 19:38:42 2004
@@ -225,11 +225,13 @@
 	if (request_resource(&iomem_resource, bus->resource[1]) < 0)
 		printk(KERN_ERR "Failed to request MEM on hose 0\n");
 
-	if (pci_mem < memtop && pci_mem > alpha_mv.min_mem_address) {
+	if (pci_mem < memtop)
+		memtop = pci_mem;
+	if (memtop > alpha_mv.min_mem_address) {
 		free_reserved_mem(__va(alpha_mv.min_mem_address),
-				  __va(pci_mem));
+				  __va(memtop));
 		printk("nautilus_init_pci: %ldk freed\n",
-			(pci_mem - alpha_mv.min_mem_address) >> 10);
+			(memtop - alpha_mv.min_mem_address) >> 10);
 	}
 
 	if ((IRONGATE0->dev_vendor >> 16) > 0x7006)	/* Albacore? */
diff -Nru a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
--- a/arch/alpha/kernel/time.c	Sat Apr  3 19:38:43 2004
+++ b/arch/alpha/kernel/time.c	Sat Apr  3 19:38:43 2004
@@ -24,6 +24,8 @@
  * 2000-08-13	Jan-Benedict Glaw <jbglaw@lug-owl.de>
  * 	Fixed time_init to be aware of epoches != 1900. This prevents
  * 	booting up in 2048 for me;) Code is stolen from rtc.c.
+ * 2003-06-03	R. Scott Bailey <scott.bailey@eds.com>
+ *	Tighten sanity in time_init from 1% (10,000 PPM) to 250 PPM
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -306,7 +308,7 @@
 time_init(void)
 {
 	unsigned int year, mon, day, hour, min, sec, cc1, cc2, epoch;
-	unsigned long cycle_freq, one_percent;
+	unsigned long cycle_freq, tolerance;
 	long diff;
 
 	/* Calibrate CPU clock -- attempt #1.  */
@@ -324,13 +326,13 @@
 
 	cycle_freq = hwrpb->cycle_freq;
 	if (est_cycle_freq) {
-		/* If the given value is within 1% of what we calculated, 
+		/* If the given value is within 250 PPM of what we calculated,
 		   accept it.  Otherwise, use what we found.  */
-		one_percent = cycle_freq / 100;
+		tolerance = cycle_freq / 4000;
 		diff = cycle_freq - est_cycle_freq;
 		if (diff < 0)
 			diff = -diff;
-		if ((unsigned long)diff > one_percent) {
+		if ((unsigned long)diff > tolerance) {
 			cycle_freq = est_cycle_freq;
 			printk("HWRPB cycle frequency bogus.  "
 			       "Estimated %lu Hz\n", cycle_freq);
diff -Nru a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
--- a/arch/alpha/kernel/traps.c	Sat Apr  3 19:38:55 2004
+++ b/arch/alpha/kernel/traps.c	Sat Apr  3 19:38:55 2004
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/smp_lock.h>
 #include <linux/module.h>
+#include <linux/init.h>
 
 #include <asm/gentrap.h>
 #include <asm/uaccess.h>
@@ -25,35 +26,37 @@
 
 #include "proto.h"
 
-/* data/code implementing a work-around for some SRMs which
-   mishandle opDEC faults
-*/
-static int opDEC_testing = 0;
-static int opDEC_fix = 0;
-static int opDEC_checked = 0;
-static unsigned long opDEC_test_pc = 0;
+/* Work-around for some SRMs which mishandle opDEC faults.  */
 
-static void
+static int opDEC_fix;
+
+static void __init
 opDEC_check(void)
 {
-	unsigned long test_pc;
-
-	if (opDEC_checked) return;
-
-	lock_kernel();
-	opDEC_testing = 1;
+	__asm__ __volatile__ (
+	/* Load the address of... */
+	"	br	$16, 1f\n"
+	/* A stub instruction fault handler.  Just add 4 to the
+	   pc and continue.  */
+	"	ldq	$16, 8($sp)\n"
+	"	addq	$16, 4, $16\n"
+	"	stq	$16, 8($sp)\n"
+	"	call_pal %[rti]\n"
+	/* Install the instruction fault handler.  */
+	"1:	lda	$17, 3\n"
+	"	call_pal %[wrent]\n"
+	/* With that in place, the fault from the round-to-minf fp
+	   insn will arrive either at the "lda 4" insn (bad) or one
+	   past that (good).  This places the correct fixup in %0.  */
+	"	lda %[fix], 0\n"
+	"	cvttq/svm $f31,$f31\n"
+	"	lda %[fix], 4"
+	: [fix] "=r" (opDEC_fix)
+	: [rti] "n" (PAL_rti), [wrent] "n" (PAL_wrent)
+	: "$0", "$1", "$16", "$17", "$22", "$23", "$24", "$25");
 
-	__asm__ __volatile__(
-		"       br      %0,1f\n"
-		"1:     addq    %0,8,%0\n"
-		"       stq     %0,%1\n"
-		"       cvttq/svm $f31,$f31\n"
-		: "=&r"(test_pc), "=m"(opDEC_test_pc)
-		: );
-
-	opDEC_testing = 0;
-	opDEC_checked = 1;
-	unlock_kernel();
+	if (opDEC_fix)
+		printk("opDEC fixup enabled.\n");
 }
 
 void
@@ -244,7 +247,7 @@
 	siginfo_t info;
 	int signo, code;
 
-	if (!opDEC_testing || type != 4) {
+	if (regs->ps == 0) {
 		if (type == 1) {
 			const unsigned int *data
 			  = (const unsigned int *) regs->pc;
@@ -359,14 +362,6 @@
 			   fault during the boot sequence and testing if
 			   we get the correct PC.  If not, we set a flag
 			   to correct it every time through.  */
-			if (opDEC_testing) {
-				if (regs->pc == opDEC_test_pc) {
-					opDEC_fix = 4;
-					regs->pc += 4;
-					printk("opDEC fixup enabled.\n");
-				}
-				return;
-			}
 			regs->pc += opDEC_fix; 
 			
 			/* EV4 does not implement anything except normal
@@ -1083,22 +1078,22 @@
 	return;
 }
 
-void
+void __init
 trap_init(void)
 {
 	/* Tell PAL-code what global pointer we want in the kernel.  */
 	register unsigned long gptr __asm__("$29");
 	wrkgp(gptr);
 
+	/* Hack for Multia (UDB) and JENSEN: some of their SRMs have
+	   a bug in the handling of the opDEC fault.  Fix it up if so.  */
+	if (implver() == IMPLVER_EV4)
+		opDEC_check();
+
 	wrent(entArith, 1);
 	wrent(entMM, 2);
 	wrent(entIF, 3);
 	wrent(entUna, 4);
 	wrent(entSys, 5);
 	wrent(entDbg, 6);
-
-	/* Hack for Multia (UDB) and JENSEN: some of their SRMs have
-	   a bug in the handling of the opDEC fault.  Fix it up if so.  */
-	if (implver() == IMPLVER_EV4)
-		opDEC_check();
 }
diff -Nru a/arch/alpha/lib/dec_and_lock.c b/arch/alpha/lib/dec_and_lock.c
--- a/arch/alpha/lib/dec_and_lock.c	Sat Apr  3 19:38:42 2004
+++ b/arch/alpha/lib/dec_and_lock.c	Sat Apr  3 19:38:42 2004
@@ -30,7 +30,7 @@
 	.previous				\n\
 	.end atomic_dec_and_lock");
 
-static int __attribute__((unused))
+static int __attribute_used__
 atomic_dec_and_lock_1(atomic_t *atomic, spinlock_t *lock)
 {
 	/* Slow path */
diff -Nru a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
--- a/arch/alpha/mm/numa.c	Sat Apr  3 19:38:41 2004
+++ b/arch/alpha/mm/numa.c	Sat Apr  3 19:38:41 2004
@@ -158,8 +158,10 @@
 	if (!nid && (node_max_pfn < end_kernel_pfn || node_min_pfn > start_kernel_pfn))
 		panic("kernel loaded out of ram");
 
-	/* Zone start phys-addr must be 2^(MAX_ORDER-1) aligned */
-	node_min_pfn = (node_min_pfn + ((1UL << (MAX_ORDER-1))-1)) & ~((1UL << (MAX_ORDER-1))-1);
+	/* Zone start phys-addr must be 2^(MAX_ORDER-1) aligned.
+	   Note that we round this down, not up - node memory
+	   has much larger alignment than 8Mb, so it's safe. */
+	node_min_pfn &= ~((1UL << (MAX_ORDER-1))-1);
 
 	/* We need to know how many physically contiguous pages
 	   we'll need for the bootmap.  */
diff -Nru a/arch/arm/Kconfig b/arch/arm/Kconfig
--- a/arch/arm/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/Kconfig	Sat Apr  3 19:38:43 2004
@@ -75,28 +75,6 @@
 config ARCH_ADIFCC
 	bool "ADIFCC-based"
 
-config ARCH_ANAKIN
-	bool "Anakin"
-	---help---
-	  The Anakin is a StrongArm based SA110 - 2 DIN Vehicle Telematics Platform.
-	  64MB SDRAM - 4 Mb Flash - Compact Flash Interface - 1 MB VRAM
-
-	  On board peripherals:
-	  * Front display: 400x234 16 bit TFT touchscreen
-	  * External independent second screen interface
-	  * CAN controller SJA1000
-	  * USB host controller
-	  * 6 channel video codec with hardware overlay
-	  * Smartcard reader
-	  * IrDa
-
-	  Modules interfaced over the Multi Media Extension slots:
-	  * A communication card
-	  Wavecom GPRS modem
-	  uBlock GPS
-	  Bosch DAB module
-	  * An audio card ( 4 * 40W, AC97 Codec, I2S)
-
 config ARCH_CLPS7500
 	bool "Cirrus-CL-PS7500FE"
 
@@ -351,7 +329,7 @@
 	help
 	  This enables the CPUfreq driver for ARM Integrator CPUs.
 
-	  For details, take a look at linux/Documentation/cpufreq.
+	  For details, take a look at linux/Documentation/cpu-freq.
 
 	  If in doubt, say Y.
 
@@ -623,12 +601,8 @@
 
 source "drivers/video/Kconfig"
 
-if ARCH_ACORN || ARCH_CLPS7500 || ARCH_TBOX || ARCH_SHARK || ARCH_SA1100 || PCI
-
 source "sound/Kconfig"
 
-endif
-
 source "drivers/misc/Kconfig"
 
 source "drivers/usb/Kconfig"
@@ -656,6 +630,15 @@
 	  print a brief message explaining what the problem was. This is
 	  sometimes helpful for debugging but serves no purpose on a
 	  production system. Most people should say N here.
+
+	  In addition, you need to pass user_debug=N on the kernel command
+	  line to enable this feature.  N consists of the sum of:
+
+	      1 - undefined instruction events
+	      2 - system calls
+	      4 - invalid data aborts
+	      8 - SIGSEGV faults
+	     16 - SIGBUS faults
 
 config DEBUG_INFO
 	bool "Include GDB debugging information in kernel binary"
diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/Makefile	Sat Apr  3 19:38:42 2004
@@ -36,7 +36,7 @@
 # Note that GCC does not numerically define an architecture version
 # macro, but instead defines a whole series of macros which makes
 # testing for a specific architecture or later rather impossible.
-arch-$(CONFIG_CPU_32v6)		:=-D__LINUX_ARM_ARCH__=6 -march=armv5t -Wa,-march=armv6
+arch-$(CONFIG_CPU_32v6)		:=-D__LINUX_ARM_ARCH__=6 $(call check_gcc,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
 arch-$(CONFIG_CPU_32v5)		:=-D__LINUX_ARM_ARCH__=5 $(call check_gcc,-march=armv5te,-march=armv4)
 arch-$(CONFIG_CPU_32v4)		:=-D__LINUX_ARM_ARCH__=4 -march=armv4
 arch-$(CONFIG_CPU_32v3)		:=-D__LINUX_ARM_ARCH__=3 -march=armv3
@@ -54,20 +54,13 @@
 tune-$(CONFIG_CPU_V6)		:=-mtune=strongarm
 
 # Need -Uarm for gcc < 3.x
-CFLAGS_BOOT	:=-mapcs-32 $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm
 CFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm
 AFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -msoft-float -Wa,-mno-fpu
 
 #Default value
 DATAADDR	:= .
 
-PROCESSOR	:= armv
 head-y		:= arch/arm/kernel/head.o arch/arm/kernel/init_task.o
-ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
-  LDFLAGS_BLOB	+= --oformat elf32-bigarm
-else
-  LDFLAGS_BLOB	+= --oformat elf32-littlearm
-endif
 textaddr-y	:= 0xC0008000
 
  machine-$(CONFIG_ARCH_ARCA5K)	   := arc
@@ -96,18 +89,16 @@
 textaddr-$(CONFIG_ARCH_CLPS711X)   := 0xc0028000
  machine-$(CONFIG_ARCH_CLPS711X)   := clps711x
 textaddr-$(CONFIG_ARCH_FORTUNET)   := 0xc0008000
- machine-$(CONFIG_ARCH_ANAKIN)	   := anakin
  machine-$(CONFIG_ARCH_IOP3XX)	   := iop3xx
  machine-$(CONFIG_ARCH_ADIFCC)	   := adifcc
 
-MACHINE  := $(machine-y)
 TEXTADDR := $(textaddr-y)
 ifeq ($(incdir-y),)
-incdir-y := $(MACHINE)
+incdir-y := $(machine-y)
 endif
 INCDIR   := $(incdir-y)
   
-export	MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT
+export	TEXTADDR GZFLAGS
 
 # Do we have FASTFPE?
 FASTFPE		:=arch/arm/fastfpe
@@ -117,8 +108,8 @@
 
 # If we have a machine-specific directory, then include it in the build.
 core-y				+= arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
-ifneq ($(MACHINE),)
-core-y				+= arch/arm/mach-$(MACHINE)/
+ifneq ($(machine-y),)
+core-y				+= arch/arm/mach-$(machine-y)/
 endif
 core-$(CONFIG_FPE_NWFPE)	+= arch/arm/nwfpe/
 core-$(CONFIG_FPE_FASTFPE)	+= $(FASTFPE_OBJ)
@@ -135,20 +126,18 @@
 boot := arch/arm/boot
 
 #	Update machine arch and proc symlinks if something which affects
-#	them changed.  We use .arch and .proc to indicate when they were
-#	updated last, otherwise make uses the target directory mtime.
+#	them changed.  We use .arch to indicate when they were updated
+#	last, otherwise make uses the target directory mtime.
 
-include/asm-arm/.arch: $(wildcard include/config/arch/*.h)
-	@echo '  Making asm-arm/arch -> asm-arm/arch-$(INCDIR) symlink'
-	@rm -f include/asm-arm/arch
-	@ln -sf arch-$(INCDIR) include/asm-arm/arch
+include/asm-arm/.arch: $(wildcard include/config/arch/*.h) include/config/MARKER
+	@echo '  SYMLINK include/asm-arm/arch -> include/asm-arm/arch-$(INCDIR)'
+	@ln -fsn arch-$(INCDIR) include/asm-arm/arch
 	@touch $@
 
-prepare: maketools
+prepare: maketools include/asm-arm/.arch
 
 .PHONY: maketools FORCE
-maketools: include/asm-arm/.arch \
-	   include/asm-arm/constants.h include/linux/version.h FORCE
+maketools: include/asm-arm/constants.h include/linux/version.h FORCE
 	$(Q)$(MAKE) $(build)=arch/arm/tools include/asm-arm/mach-types.h
 
 # Convert bzImage to zImage
@@ -161,8 +150,8 @@
 zinstall install: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) $@
 
-CLEAN_FILES += include/asm-arm/constants.h* include/asm-arm/mach-types.h
-MRPROPER_FILES += include/asm-arm/arch include/asm-arm/.arch
+CLEAN_FILES += include/asm-arm/constants.h* include/asm-arm/mach-types.h \
+	       include/asm-arm/arch include/asm-arm/.arch
 
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
@@ -176,8 +165,7 @@
 zi:;	$(Q)$(MAKE) $(build)=$(boot) zinstall
 
 arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
-				   include/asm-arm/.arch \
-				   include/config/MARKER
+				   include/asm-arm/.arch
 
 include/asm-$(ARCH)/constants.h: arch/$(ARCH)/kernel/asm-offsets.s
 	$(call filechk,gen-asm-offsets)
diff -Nru a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
--- a/arch/arm/boot/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/boot/Makefile	Sat Apr  3 19:38:41 2004
@@ -47,7 +47,6 @@
 params_phys-$(CONFIG_ARCH_SA1100)	:= 0xc0000100
 initrd_phys-$(CONFIG_ARCH_SA1100)	:= 0xc0800000
    zreladdr-$(CONFIG_ARCH_PXA)		:= 0xa0008000
-   zreladdr-$(CONFIG_ARCH_ANAKIN)	:= 0x20008000
    zreladdr-$(CONFIG_ARCH_IOP3XX)	:= 0xa0008000
 params_phys-$(CONFIG_ARCH_IOP3XX)	:= 0xa0000100
    zreladdr-$(CONFIG_ARCH_ADIFCC)	:= 0xc0008000
@@ -82,7 +81,7 @@
 	$(call if_changed,objcopy)
 	@echo '  Kernel: $@ is ready'
 
-quite_cmd_uimage = UIMAGE $@
+quiet_cmd_uimage = UIMAGE  $@
       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
 		   -C none -a $(ZRELADDR) -e $(ZRELADDR) \
 		   -n 'Linux-$(KERNELRELEASE)' -d $< $@
diff -Nru a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
--- a/arch/arm/boot/compressed/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/boot/compressed/Makefile	Sat Apr  3 19:38:41 2004
@@ -59,7 +59,7 @@
 
 targets       := vmlinux vmlinux.lds piggy piggy.gz piggy.o \
                  font.o head.o $(OBJS)
-EXTRA_CFLAGS  := $(CFLAGS_BOOT) -fpic
+EXTRA_CFLAGS  := -fpic
 EXTRA_AFLAGS  := -traditional
 
 LDFLAGS_vmlinux := -p -X \
diff -Nru a/arch/arm/common/amba.c b/arch/arm/common/amba.c
--- a/arch/arm/common/amba.c	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/common/amba.c	Sat Apr  3 19:38:43 2004
@@ -199,7 +199,11 @@
 
 	dev->dev.release = amba_device_release;
 	dev->dev.bus = &amba_bustype;
+	dev->dev.dma_mask = &dev->dma_mask;
 	dev->res.name = dev->dev.bus_id;
+
+	if (!dev->dev.coherent_dma_mask && dev->dma_mask)
+		dev_warn(&dev->dev, "coherent dma mask is unset\n");
 
 	ret = request_resource(parent, &dev->res);
 	if (ret == 0) {
diff -Nru a/arch/arm/common/sa1111-pcibuf.c b/arch/arm/common/sa1111-pcibuf.c
--- a/arch/arm/common/sa1111-pcibuf.c	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/common/sa1111-pcibuf.c	Sat Apr  3 19:38:40 2004
@@ -457,8 +457,8 @@
 	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 @@
 	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_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 -Nru a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
--- a/arch/arm/common/sa1111.c	Sat Apr  3 19:38:55 2004
+++ b/arch/arm/common/sa1111.c	Sat Apr  3 19:38:55 2004
@@ -516,6 +516,8 @@
 	 */
 	if (sachip->dev->dma_mask)
 		*sachip->dev->dma_mask &= sa1111_dma_mask[drac >> 2];
+
+	sachip->dev->coherent_dma_mask &= sa1111_dma_mask[drac >> 2];
 }
 
 #endif
@@ -558,6 +560,7 @@
 	dev->dev.parent  = sachip->dev;
 	dev->dev.bus     = &sa1111_bus_type;
 	dev->dev.release = sa1111_dev_release;
+	dev->dev.coherent_dma_mask = sachip->dev->coherent_dma_mask;
 	dev->res.start   = sachip->phys + info->offset;
 	dev->res.end     = dev->res.start + 511;
 	dev->res.name    = dev->dev.bus_id;
diff -Nru a/arch/arm/configs/a5k_defconfig b/arch/arm/configs/a5k_defconfig
--- a/arch/arm/configs/a5k_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/a5k_defconfig	Sat Apr  3 19:38:42 2004
@@ -317,9 +317,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_I2C_ALGOPCF is not set
 CONFIG_I2C_CHARDEV=y
 
diff -Nru a/arch/arm/configs/adi_evb_defconfig b/arch/arm/configs/adi_evb_defconfig
--- a/arch/arm/configs/adi_evb_defconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/configs/adi_evb_defconfig	Sat Apr  3 19:38:43 2004
@@ -28,7 +28,6 @@
 # System Type
 #
 CONFIG_ARCH_ADIFCC=y
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -417,8 +416,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
diff -Nru a/arch/arm/configs/adsbitsy_defconfig b/arch/arm/configs/adsbitsy_defconfig
--- a/arch/arm/configs/adsbitsy_defconfig	Sat Apr  3 19:38:45 2004
+++ b/arch/arm/configs/adsbitsy_defconfig	Sat Apr  3 19:38:45 2004
@@ -25,7 +25,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -581,7 +580,6 @@
 # CONFIG_FB_CLPS711X is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_SA1100=y
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_E1355 is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
diff -Nru a/arch/arm/configs/assabet_defconfig b/arch/arm/configs/assabet_defconfig
--- a/arch/arm/configs/assabet_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/assabet_defconfig	Sat Apr  3 19:38:42 2004
@@ -27,7 +27,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -527,8 +526,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -773,7 +770,6 @@
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FB_ACORN is not set
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_CLPS711X is not set
 CONFIG_FB_SA1100=y
 # CONFIG_FB_CYBER2000 is not set
diff -Nru a/arch/arm/configs/badge4_defconfig b/arch/arm/configs/badge4_defconfig
--- a/arch/arm/configs/badge4_defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/arm/configs/badge4_defconfig	Sat Apr  3 19:38:55 2004
@@ -35,7 +35,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -654,8 +653,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -690,9 +687,6 @@
 #
 CONFIG_I2C=m
 CONFIG_I2C_ALGOBIT=m
-# CONFIG_I2C_PHILIPSPAR is not set
-CONFIG_I2C_ELV=m
-CONFIG_I2C_VELLEMAN=m
 # CONFIG_I2C_BIT_SA1100_GPIO is not set
 CONFIG_I2C_ALGOPCF=m
 CONFIG_I2C_ELEKTOR=m
@@ -735,7 +729,6 @@
 CONFIG_SA1100_WATCHDOG=m
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_60XX_WDT is not set
 # CONFIG_W83877F_WDT is not set
diff -Nru a/arch/arm/configs/cerfcube_defconfig b/arch/arm/configs/cerfcube_defconfig
--- a/arch/arm/configs/cerfcube_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/configs/cerfcube_defconfig	Sat Apr  3 19:38:40 2004
@@ -45,7 +45,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -449,7 +448,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -573,7 +571,6 @@
 CONFIG_SA1100_WATCHDOG=m
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_SCx200_WDT is not set
 # CONFIG_60XX_WDT is not set
diff -Nru a/arch/arm/configs/clps7500_defconfig b/arch/arm/configs/clps7500_defconfig
--- a/arch/arm/configs/clps7500_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/configs/clps7500_defconfig	Sat Apr  3 19:38:40 2004
@@ -340,9 +340,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_I2C_ALGOPCF is not set
 # CONFIG_I2C_CHARDEV is not set
 
diff -Nru a/arch/arm/configs/ebsa110_defconfig b/arch/arm/configs/ebsa110_defconfig
--- a/arch/arm/configs/ebsa110_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/configs/ebsa110_defconfig	Sat Apr  3 19:38:40 2004
@@ -35,7 +35,6 @@
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_ANAKIN is not set
 
 #
 # Archimedes/A5000 Implementations
@@ -475,7 +474,6 @@
 # CONFIG_ADVANTECH_WDT is not set
 # CONFIG_60XX_WDT is not set
 # CONFIG_MIXCOMWD is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MACHZ_WDT is not set
 # CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
diff -Nru a/arch/arm/configs/epxa10db_defconfig b/arch/arm/configs/epxa10db_defconfig
--- a/arch/arm/configs/epxa10db_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/epxa10db_defconfig	Sat Apr  3 19:38:42 2004
@@ -32,7 +32,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
diff -Nru a/arch/arm/configs/flexanet_defconfig b/arch/arm/configs/flexanet_defconfig
--- a/arch/arm/configs/flexanet_defconfig	Sat Apr  3 19:38:56 2004
+++ b/arch/arm/configs/flexanet_defconfig	Sat Apr  3 19:38:56 2004
@@ -27,7 +27,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -513,8 +512,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -716,7 +713,6 @@
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FB_ACORN is not set
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_CLPS711X is not set
 CONFIG_FB_SA1100=y
 # CONFIG_FB_CYBER2000 is not set
diff -Nru a/arch/arm/configs/footbridge_defconfig b/arch/arm/configs/footbridge_defconfig
--- a/arch/arm/configs/footbridge_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/footbridge_defconfig	Sat Apr  3 19:38:42 2004
@@ -525,7 +525,6 @@
 # CONFIG_ACQUIRE_WDT is not set
 # CONFIG_60XX_WDT is not set
 # CONFIG_MIXCOMWD is not set
-# CONFIG_I810_TCO is not set
 CONFIG_21285_WATCHDOG=m
 CONFIG_977_WATCHDOG=m
 CONFIG_DS1620=y
diff -Nru a/arch/arm/configs/fortunet_defconfig b/arch/arm/configs/fortunet_defconfig
--- a/arch/arm/configs/fortunet_defconfig	Sat Apr  3 19:38:56 2004
+++ b/arch/arm/configs/fortunet_defconfig	Sat Apr  3 19:38:56 2004
@@ -27,7 +27,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 CONFIG_ARCH_CLPS711X=y
@@ -343,8 +342,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 CONFIG_SERIAL_CLPS711X=y
diff -Nru a/arch/arm/configs/graphicsclient_defconfig b/arch/arm/configs/graphicsclient_defconfig
--- a/arch/arm/configs/graphicsclient_defconfig	Sat Apr  3 19:38:56 2004
+++ b/arch/arm/configs/graphicsclient_defconfig	Sat Apr  3 19:38:56 2004
@@ -25,7 +25,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -687,7 +686,6 @@
 # CONFIG_FB_CLPS711X is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_SA1100=y
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_E1355 is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
diff -Nru a/arch/arm/configs/graphicsmaster_defconfig b/arch/arm/configs/graphicsmaster_defconfig
--- a/arch/arm/configs/graphicsmaster_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/configs/graphicsmaster_defconfig	Sat Apr  3 19:38:40 2004
@@ -25,7 +25,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -662,7 +661,6 @@
 # CONFIG_FB_CLPS711X is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_SA1100=y
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_E1355 is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
diff -Nru a/arch/arm/configs/h3600_defconfig b/arch/arm/configs/h3600_defconfig
--- a/arch/arm/configs/h3600_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/h3600_defconfig	Sat Apr  3 19:38:42 2004
@@ -27,7 +27,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -516,8 +515,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -753,7 +750,6 @@
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FB_ACORN is not set
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_CLPS711X is not set
 CONFIG_FB_SA1100=y
 # CONFIG_FB_CYBER2000 is not set
diff -Nru a/arch/arm/configs/hackkit_defconfig b/arch/arm/configs/hackkit_defconfig
--- a/arch/arm/configs/hackkit_defconfig	Sat Apr  3 19:38:57 2004
+++ b/arch/arm/configs/hackkit_defconfig	Sat Apr  3 19:38:57 2004
@@ -32,7 +32,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
diff -Nru a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig
--- a/arch/arm/configs/integrator_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/configs/integrator_defconfig	Sat Apr  3 19:38:41 2004
@@ -35,7 +35,6 @@
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_ANAKIN is not set
 
 #
 # Archimedes/A5000 Implementations
@@ -620,7 +619,6 @@
 # CONFIG_FB_CLPS711X is not set
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_SA1100 is not set
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_E1355 is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_ATY is not set
diff -Nru a/arch/arm/configs/iq80310_defconfig b/arch/arm/configs/iq80310_defconfig
--- a/arch/arm/configs/iq80310_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/configs/iq80310_defconfig	Sat Apr  3 19:38:41 2004
@@ -39,7 +39,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
diff -Nru a/arch/arm/configs/iq80321_defconfig b/arch/arm/configs/iq80321_defconfig
--- a/arch/arm/configs/iq80321_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/iq80321_defconfig	Sat Apr  3 19:38:42 2004
@@ -39,7 +39,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
diff -Nru a/arch/arm/configs/jornada720_defconfig b/arch/arm/configs/jornada720_defconfig
--- a/arch/arm/configs/jornada720_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/jornada720_defconfig	Sat Apr  3 19:38:42 2004
@@ -27,7 +27,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -518,8 +517,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -730,7 +727,6 @@
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FB_ACORN is not set
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_CLPS711X is not set
 # CONFIG_FB_SA1100 is not set
 CONFIG_FB_EPSON1356=y
diff -Nru a/arch/arm/configs/lart_defconfig b/arch/arm/configs/lart_defconfig
--- a/arch/arm/configs/lart_defconfig	Sat Apr  3 19:38:57 2004
+++ b/arch/arm/configs/lart_defconfig	Sat Apr  3 19:38:57 2004
@@ -44,7 +44,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -470,7 +469,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/arm/configs/lubbock_defconfig b/arch/arm/configs/lubbock_defconfig
--- a/arch/arm/configs/lubbock_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/configs/lubbock_defconfig	Sat Apr  3 19:38:41 2004
@@ -35,7 +35,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -583,8 +582,6 @@
 #
 # CONFIG_ATOMWIDE_SERIAL is not set
 # CONFIG_DUALSP_SERIAL is not set
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
diff -Nru a/arch/arm/configs/lusl7200_defconfig b/arch/arm/configs/lusl7200_defconfig
--- a/arch/arm/configs/lusl7200_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/configs/lusl7200_defconfig	Sat Apr  3 19:38:41 2004
@@ -35,7 +35,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -314,8 +313,6 @@
 #
 # CONFIG_ATOMWIDE_SERIAL is not set
 # CONFIG_DUALSP_SERIAL is not set
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
diff -Nru a/arch/arm/configs/neponset_defconfig b/arch/arm/configs/neponset_defconfig
--- a/arch/arm/configs/neponset_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/neponset_defconfig	Sat Apr  3 19:38:42 2004
@@ -31,7 +31,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -500,8 +499,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_SCx200_ACB is not set
 CONFIG_I2C_BIT_SA1100_GPIO=y
 # CONFIG_I2C_ALGOPCF is not set
@@ -536,7 +533,6 @@
 CONFIG_SA1100_WATCHDOG=m
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_SCx200_WDT is not set
 # CONFIG_60XX_WDT is not set
diff -Nru a/arch/arm/configs/netwinder_defconfig b/arch/arm/configs/netwinder_defconfig
--- a/arch/arm/configs/netwinder_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/configs/netwinder_defconfig	Sat Apr  3 19:38:41 2004
@@ -40,7 +40,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -464,7 +463,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -617,7 +615,6 @@
 CONFIG_977_WATCHDOG=y
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_SCx200_WDT is not set
 # CONFIG_60XX_WDT is not set
diff -Nru a/arch/arm/configs/pangolin_defconfig b/arch/arm/configs/pangolin_defconfig
--- a/arch/arm/configs/pangolin_defconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/configs/pangolin_defconfig	Sat Apr  3 19:38:43 2004
@@ -25,7 +25,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -662,7 +661,6 @@
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_SA1100 is not set
 CONFIG_FB_MQ200=y
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_E1355 is not set
 # CONFIG_FB_VIRTUAL is not set
 CONFIG_FBCON_ADVANCED=y
diff -Nru a/arch/arm/configs/pfs168_mqtft_defconfig b/arch/arm/configs/pfs168_mqtft_defconfig
--- a/arch/arm/configs/pfs168_mqtft_defconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/configs/pfs168_mqtft_defconfig	Sat Apr  3 19:38:43 2004
@@ -506,9 +506,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_I2C_ASSABET is not set
 CONFIG_I2C_PFS168=y
 # CONFIG_I2C_ALGOPCF is not set
diff -Nru a/arch/arm/configs/pfs168_mqvga_defconfig b/arch/arm/configs/pfs168_mqvga_defconfig
--- a/arch/arm/configs/pfs168_mqvga_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/configs/pfs168_mqvga_defconfig	Sat Apr  3 19:38:40 2004
@@ -506,9 +506,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_I2C_ASSABET is not set
 CONFIG_I2C_PFS168=y
 # CONFIG_I2C_ALGOPCF is not set
diff -Nru a/arch/arm/configs/pfs168_sastn_defconfig b/arch/arm/configs/pfs168_sastn_defconfig
--- a/arch/arm/configs/pfs168_sastn_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/configs/pfs168_sastn_defconfig	Sat Apr  3 19:38:41 2004
@@ -507,9 +507,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_I2C_ASSABET is not set
 # CONFIG_I2C_ALGOPCF is not set
 CONFIG_I2C_CHARDEV=y
diff -Nru a/arch/arm/configs/pfs168_satft_defconfig b/arch/arm/configs/pfs168_satft_defconfig
--- a/arch/arm/configs/pfs168_satft_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/configs/pfs168_satft_defconfig	Sat Apr  3 19:38:40 2004
@@ -506,9 +506,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_I2C_ASSABET is not set
 CONFIG_I2C_PFS168=y
 # CONFIG_I2C_ALGOPCF is not set
diff -Nru a/arch/arm/configs/pleb_defconfig b/arch/arm/configs/pleb_defconfig
--- a/arch/arm/configs/pleb_defconfig	Sat Apr  3 19:38:54 2004
+++ b/arch/arm/configs/pleb_defconfig	Sat Apr  3 19:38:54 2004
@@ -35,7 +35,6 @@
 # CONFIG_ARCH_RPC is not set
 CONFIG_ARCH_SA1100=y
 # CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_ANAKIN is not set
 
 #
 # Archimedes/A5000 Implementations
diff -Nru a/arch/arm/configs/rpc_defconfig b/arch/arm/configs/rpc_defconfig
--- a/arch/arm/configs/rpc_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/configs/rpc_defconfig	Sat Apr  3 19:38:40 2004
@@ -31,7 +31,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -462,9 +461,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_ALGOPCF is not set
 CONFIG_I2C_CHARDEV=y
diff -Nru a/arch/arm/configs/shannon_defconfig b/arch/arm/configs/shannon_defconfig
--- a/arch/arm/configs/shannon_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/configs/shannon_defconfig	Sat Apr  3 19:38:41 2004
@@ -27,7 +27,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -476,7 +475,6 @@
 CONFIG_SA1100_WATCHDOG=y
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_60XX_WDT is not set
 # CONFIG_W83877F_WDT is not set
diff -Nru a/arch/arm/configs/shark_defconfig b/arch/arm/configs/shark_defconfig
--- a/arch/arm/configs/shark_defconfig	Sat Apr  3 19:38:45 2004
+++ b/arch/arm/configs/shark_defconfig	Sat Apr  3 19:38:45 2004
@@ -46,7 +46,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
@@ -382,7 +381,6 @@
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/arm/configs/stork_defconfig b/arch/arm/configs/stork_defconfig
--- a/arch/arm/configs/stork_defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/arm/configs/stork_defconfig	Sat Apr  3 19:38:55 2004
@@ -28,7 +28,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -514,8 +513,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -753,7 +750,6 @@
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FB_ACORN is not set
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_CLPS711X is not set
 CONFIG_FB_SA1100=y
 # CONFIG_FB_CYBER2000 is not set
diff -Nru a/arch/arm/configs/system3_defconfig b/arch/arm/configs/system3_defconfig
--- a/arch/arm/configs/system3_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/configs/system3_defconfig	Sat Apr  3 19:38:42 2004
@@ -27,7 +27,6 @@
 #
 # System Type
 #
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -532,8 +531,6 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -799,7 +796,6 @@
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FB_ACORN is not set
-# CONFIG_FB_ANAKIN is not set
 # CONFIG_FB_CLPS711X is not set
 CONFIG_FB_SA1100=y
 # CONFIG_FB_CYBER2000 is not set
diff -Nru a/arch/arm/configs/trizeps_defconfig b/arch/arm/configs/trizeps_defconfig
--- a/arch/arm/configs/trizeps_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/configs/trizeps_defconfig	Sat Apr  3 19:38:40 2004
@@ -35,7 +35,6 @@
 # System Type
 #
 # CONFIG_ARCH_ADIFCC is not set
-# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
@@ -494,7 +493,6 @@
 # CONFIG_BLK_DEV_IDE_RAPIDE is not set
 # CONFIG_IDE_CHIPSETS is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 
 #
 # SCSI support
@@ -601,8 +599,6 @@
 # CONFIG_SERIAL_8250_MULTIPORT is not set
 # CONFIG_SERIAL_8250_RSA is not set
 # CONFIG_SERIAL_ACORN is not set
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -624,9 +620,6 @@
 #
 CONFIG_I2C=m
 CONFIG_I2C_ALGOBIT=m
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 # CONFIG_SCx200_I2C is not set
 # CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_BIT_SA1100_GPIO is not set
diff -Nru a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
--- a/arch/arm/kernel/Makefile	Sat Apr  3 19:38:55 2004
+++ b/arch/arm/kernel/Makefile	Sat Apr  3 19:38:55 2004
@@ -20,7 +20,7 @@
 obj-$(CONFIG_ISA_DMA)		+= dma-isa.o
 obj-$(CONFIG_PCI)		+= bios32.o
 
-ifneq ($(MACHINE),ebsa110)
+ifneq ($(CONFIG_ARCH_EBSA110),y)
   obj-y		+= io.o
 endif
 
diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
--- a/arch/arm/kernel/armksyms.c	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/kernel/armksyms.c	Sat Apr  3 19:38:42 2004
@@ -88,10 +88,6 @@
 EXPORT_SYMBOL_ALIAS(fp_printk,printk);
 EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig);
 
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(kd_mksound);
-#endif
-
 EXPORT_SYMBOL_NOVERS(__do_softirq);
 EXPORT_SYMBOL_NOVERS(__backtrace);
 
@@ -188,11 +184,6 @@
 EXPORT_SYMBOL(__arch_clear_user);
 EXPORT_SYMBOL(__arch_strnlen_user);
 EXPORT_SYMBOL(__arch_strncpy_from_user);
-
-	/* consistent area handling */
-EXPORT_SYMBOL(consistent_alloc);
-EXPORT_SYMBOL(consistent_free);
-EXPORT_SYMBOL(consistent_sync);
 
 EXPORT_SYMBOL_NOVERS(__get_user_1);
 EXPORT_SYMBOL_NOVERS(__get_user_2);
diff -Nru a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S
--- a/arch/arm/kernel/debug.S	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/kernel/debug.S	Sat Apr  3 19:38:42 2004
@@ -348,37 +348,6 @@
 1002:
 		.endm
 
-#elif defined(CONFIG_ARCH_ANAKIN)
-
-//#//include <asm/arch/serial_reg.h>
-
-		.macro	addruart,rx
-		mrc	p15, 0, \rx, c1, c0
-		tst	\rx, #1			@ MMU enabled?
-		moveq	\rx, #IO_START
-		movne	\rx, #IO_BASE
-		add	\rx, \rx, #UART0
-		.endm
-
-		.macro	senduart,rd,rx
-		str	\rd, [\rx, #0x14]	@ tx
-		ldr	\rd, [\rx, #0x18]
-		orr	\rd, \rd, #SENDREQUEST
-		str	\rd, [\rx, #0x18]
-		.endm
-
-		.macro	waituart,rd,rx
-1001:		ldr	\rd, [\rx, #0x10]
-		tst	\rd, #TXEMPTY
-		beq	1001b
-		.endm
-
-		.macro	busyuart,rd,rx
-1001:		ldr	\rd, [\rx, #0x10]
-		tst	\rd, #CTS
-		bne	1001b
-		.endm
-
 #elif defined(CONFIG_ARCH_CAMELOT)
 
 #include <asm/arch/excalibur.h>
diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
--- a/arch/arm/kernel/entry-armv.S	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/kernel/entry-armv.S	Sat Apr  3 19:38:42 2004
@@ -530,33 +530,6 @@
 		.macro	irq_prio_table
 		.endm
 
-#elif defined(CONFIG_ARCH_ANAKIN)
-
-		.macro	disable_fiq
-		.endm
-
-		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-		mov	\base, #IO_BASE
-		mov	\irqstat, #INTERRUPT_CONTROLLER
-		ldr	\tmp, =anakin_irq_mask
-		ldr	\irqstat, [\base, \irqstat]
-		ldr	\tmp, [\tmp]
-		ands	\irqstat, \irqstat, \tmp
-		ldrne	\tmp, =anakin_active_irqs
-		strne	\irqstat, [\tmp]
-		movne	\irqnr, #IRQ_ANAKIN
-		.endm
-
-		.macro	irq_prio_table
-		.ltorg
-		.bss
-ENTRY(anakin_irq_mask)
-		.word	0
-ENTRY(anakin_active_irqs)
-		.space	4
-		.text
-		.endm
-
 #elif defined(CONFIG_ARCH_IOP310) || defined(CONFIG_ARCH_ADIFCC)
 
 		.macro	disable_fiq
diff -Nru a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
--- a/arch/arm/kernel/sys_arm.c	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/kernel/sys_arm.c	Sat Apr  3 19:38:41 2004
@@ -100,7 +100,7 @@
 	struct mmap_arg_struct a;
 
 	if (copy_from_user(&a, arg, sizeof(a)))
-		goto out;;
+		goto out;
 
 	error = -EINVAL;
 	if (a.offset & ~PAGE_MASK)
diff -Nru a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
--- a/arch/arm/kernel/time.c	Sat Apr  3 19:38:54 2004
+++ b/arch/arm/kernel/time.c	Sat Apr  3 19:38:54 2004
@@ -143,6 +143,54 @@
 
 void (*leds_event)(led_event_t) = dummy_leds_event;
 
+struct leds_evt_name {
+	const char	name[8];
+	int		on;
+	int		off;
+};
+
+static const struct leds_evt_name evt_names[] = {
+	{ "amber", led_amber_on, led_amber_off },
+	{ "blue",  led_blue_on,  led_blue_off  },
+	{ "green", led_green_on, led_green_off },
+	{ "red",   led_red_on,   led_red_off   },
+};
+
+static ssize_t leds_store(struct sys_device *dev, const char *buf, size_t size)
+{
+	int ret = -EINVAL, len = strcspn(buf, " ");
+
+	if (len > 0 && buf[len] == '\0')
+		len--;
+
+	if (strncmp(buf, "claim", len) == 0) {
+		leds_event(led_claim);
+		ret = size;
+	} else if (strncmp(buf, "release", len) == 0) {
+		leds_event(led_release);
+		ret = size;
+	} else {
+		int i;
+
+		for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
+			if (strlen(evt_names[i].name) != len ||
+			    strncmp(buf, evt_names[i].name, len) != 0)
+				continue;
+			if (strncmp(buf+len, " on", 3) == 0) {
+				leds_event(evt_names[i].on);
+				ret = size;
+			} else if (strncmp(buf+len, " off", 4) == 0) {
+				leds_event(evt_names[i].off);
+				ret = size;
+			}
+			break;
+		}
+	}
+	return ret;
+}
+
+static SYSDEV_ATTR(event, 0200, NULL, leds_store);
+
 static int leds_suspend(struct sys_device *dev, u32 state)
 {
 	leds_event(led_stop);
@@ -179,6 +227,8 @@
 	ret = sysdev_class_register(&leds_sysclass);
 	if (ret == 0)
 		ret = sysdev_register(&leds_device);
+	if (ret == 0)
+		ret = sysdev_create_file(&leds_device, &attr_event);
 	return ret;
 }
 
diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
--- a/arch/arm/kernel/traps.c	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/kernel/traps.c	Sat Apr  3 19:38:43 2004
@@ -50,6 +50,17 @@
 
 static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
 
+#ifdef CONFIG_DEBUG_USER
+unsigned int user_debug;
+
+static int __init user_debug_setup(char *str)
+{
+	get_option(&str, &user_debug);
+	return 1;
+}
+__setup("user_debug=", user_debug_setup);
+#endif
+
 void dump_backtrace_entry(unsigned long where, unsigned long from)
 {
 #ifdef CONFIG_KALLSYMS
@@ -287,9 +298,11 @@
 	spin_unlock_irq(&undef_lock);
 
 #ifdef CONFIG_DEBUG_USER
-	printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
-		current->comm, current->pid, pc);
-	dump_instr(regs);
+	if (user_debug & UDBG_UNDEFINED) {
+		printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
+			current->comm, current->pid, pc);
+		dump_instr(regs);
+	}
 #endif
 
 	current->thread.error_code = 0;
@@ -351,9 +364,11 @@
 	}
 
 #ifdef CONFIG_DEBUG_USER
-	printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
-		current->pid, current->comm, n);
-	dump_instr(regs);
+	if (user_debug & UDBG_SYSCALL) {
+		printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
+			current->pid, current->comm, n);
+		dump_instr(regs);
+	}
 #endif
 
 	info.si_signo = SIGILL;
@@ -459,11 +474,14 @@
 	 * experience shows that these seem to indicate that
 	 * something catastrophic has happened
 	 */
-	printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no);
-	dump_instr(regs);
-	if (user_mode(regs)) {
-		show_regs(regs);
-		c_backtrace(regs->ARM_fp, processor_mode(regs));
+	if (user_debug & UDBG_SYSCALL) {
+		printk("[%d] %s: arm syscall %d\n",
+		       current->pid, current->comm, no);
+		dump_instr(regs);
+		if (user_mode(regs)) {
+			show_regs(regs);
+			c_backtrace(regs->ARM_fp, processor_mode(regs));
+		}
 	}
 #endif
 	info.si_signo = SIGILL;
@@ -495,10 +513,12 @@
 	siginfo_t info;
 
 #ifdef CONFIG_DEBUG_USER
-	printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
-		current->pid, current->comm, code, instr);
-	dump_instr(regs);
-	show_pte(current->mm, addr);
+	if (user_debug & UDBG_BADABORT) {
+		printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
+			current->pid, current->comm, code, instr);
+		dump_instr(regs);
+		show_pte(current->mm, addr);
+	}
 #endif
 
 	info.si_signo = SIGILL;
diff -Nru a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
--- a/arch/arm/lib/Makefile	Sat Apr  3 19:38:45 2004
+++ b/arch/arm/lib/Makefile	Sat Apr  3 19:38:45 2004
@@ -11,30 +11,20 @@
 		   strnlen_user.o strchr.o strrchr.o testchangebit.o  \
 		   testclearbit.o testsetbit.o uaccess.o getuser.o    \
 		   putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o   \
-		   ucmpdi2.o udivdi3.o lib1funcs.o div64.o
-
-lib-arc		:= ecard.o io-acorn.o floppydma.o
-lib-rpc		:= ecard.o io-acorn.o floppydma.o
-lib-clps7500	:= io-acorn.o
-lib-l7200     	:= io-acorn.o
-lib-shark	:= io-shark.o
-lib-edb7211	:= io-acorn.o
-
-lib-y		+= $(lib-$(MACHINE))
+		   ucmpdi2.o udivdi3.o lib1funcs.o div64.o	      \
+		   io-readsb.o io-writesb.o io-writesl.o
 
 ifeq ($(CONFIG_CPU_32v3),y)
-  v3		:= y
-  v4		:= n
+  lib-y	+= io-readsw-armv3.o io-writesw-armv3.o io-readsl-armv3.o
 else
-  v3		:= n
-  v4		:= y
+  lib-y	+= io-readsw-armv4.o io-writesw-armv4.o io-readsl-armv4.o
 endif
 
-lib-y		+= io-readsb.o io-writesb.o
-lib-$(v3)	+= io-readsw-armv3.o io-writesw-armv3.o io-readsl-armv3.o
-lib-$(v4)	+= io-readsw-armv4.o io-writesw-armv4.o io-readsl-armv4.o
-lib-y		+= io-writesl.o
+lib-$(CONFIG_ARCH_RPC)		+= ecard.o io-acorn.o floppydma.o
+lib-$(CONFIG_ARCH_CLPS7500)	+= io-acorn.o
+lib-$(CONFIG_ARCH_L7200)	+= io-acorn.o
+lib-$(CONFIG_ARCH_SHARK)	+= io-shark.o
+lib-$(CONFIG_ARCH_CLPS711X)	+= io-acorn.o
 
 $(obj)/csumpartialcopy.o:	$(obj)/csumpartialcopygeneric.S
 $(obj)/csumpartialcopyuser.o:	$(obj)/csumpartialcopygeneric.S
-
diff -Nru a/arch/arm/mach-anakin/Makefile b/arch/arm/mach-anakin/Makefile
--- a/arch/arm/mach-anakin/Makefile	Sat Apr  3 19:38:44 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,11 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
-obj-y			:= arch.o irq.o mm.o
-obj-m			:=
-obj-n			:=
-obj-			:=
-
diff -Nru a/arch/arm/mach-anakin/arch.c b/arch/arm/mach-anakin/arch.c
--- a/arch/arm/mach-anakin/arch.c	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,29 +0,0 @@
-/*
- *  linux/arch/arm/mach-anakin/arch.c
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   09-Apr-2001 W/TTC	Created
- */
-#include <linux/tty.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-extern void anakin_map_io(void);
-extern void genarch_init_irq(void);
-
-MACHINE_START(ANAKIN, "Anakin")
-	MAINTAINER("Wookey/Tak-Shing Chan")
-	BOOT_MEM(0x20000000, 0x40000000, 0xe0000000)
-	VIDEO(0x80000000, 0x8002db40)
-	MAPIO(anakin_map_io)
-	INITIRQ(genarch_init_irq)
-MACHINE_END
diff -Nru a/arch/arm/mach-anakin/irq.c b/arch/arm/mach-anakin/irq.c
--- a/arch/arm/mach-anakin/irq.c	Sat Apr  3 19:38:44 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,83 +0,0 @@
-/*
- *  linux/arch/arm/mach-anakin/irq.c
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   10-Apr-2001 TTC	Created
- */
-
-#include <linux/ptrace.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/mach/irq.h>
-
-extern unsigned int anakin_irq_mask, anakin_active_irqs;
-extern void do_IRQ(int, struct pt_regs *);
-
-static void
-anakin_mask_irq(unsigned int irq)
-{
-	anakin_irq_mask &= ~(1 << irq);
-}
-
-static void
-anakin_unmask_irq(unsigned int irq)
-{
-	anakin_irq_mask |= (1 << irq);
-}
-
-/*
- * This is a faked interrupt to deal with parallel interrupt requests
- * on the Anakin.  Make sure that its interrupt number is not in any
- * way conflicting with the hardware interrupt numbers!  Check
- * IRQ_ANAKIN in linux/include/asm-arm/arch-anakin/irqs.h.
- */
-static void
-anakin_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	for (irq = 0; irq < NR_IRQS; irq++)
-		if (anakin_active_irqs & (1 << irq))
-			do_IRQ(irq, regs);
-}
-
-static struct irqaction anakin_irq = {
-	.name		= "Anakin IRQ",
-	.handler	= anakin_interrupt,
-	.flags		= SA_INTERRUPT
-};
- 
-void __init
-irq_init_irq(void)
-{
-	unsigned int irq;
-
-	for (irq = 0; irq < NR_IRQS; irq++) {
-		switch (irq) {
-		case IRQ_UART0:
-		case IRQ_UART1:
-		case IRQ_UART2:
-		case IRQ_TICK:
-		case IRQ_CODEC:
-		case IRQ_UART4:
-		case IRQ_TOUCHSCREEN:
-		case IRQ_UART3:
-		case IRQ_FIFO:
-		case IRQ_CAN:
-		case IRQ_COMPACTFLASH:
-		case IRQ_BOSH:
-		case IRQ_ANAKIN:
-			irq_desc[irq].valid = 1;
-			irq_desc[irq].mask_ack = anakin_mask_irq;
-			irq_desc[irq].mask = anakin_mask_irq;
-			irq_desc[irq].unmask = anakin_unmask_irq;
-		}
-	}
-	setup_arm_irq(IRQ_ANAKIN, &anakin_irq);
-}
diff -Nru a/arch/arm/mach-anakin/mm.c b/arch/arm/mach-anakin/mm.c
--- a/arch/arm/mach-anakin/mm.c	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- *  linux/arch/arm/mach-anakin/mm.c
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   09-Apr-2001 W/TTC	Created
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/mach/map.h>
-
-static struct map_desc anakin_io_desc[] __initdata = {
-	{ IO_BASE,    IO_START,    IO_SIZE,    MT_DEVICE },
-	{ FLASH_BASE, FLASH_START, FLASH_SIZE, MT_DEVICE },
-	{ VGA_BASE,   VGA_START,   VGA_SIZE,   MT_DEVICE }
-};
-
-void __init
-anakin_map_io(void)
-{
-	iotable_init(anakin_io_desc, ARRAY_SIZE(anakin_io_desc));
-}
diff -Nru a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig
--- a/arch/arm/mach-sa1100/Kconfig	Sat Apr  3 19:38:57 2004
+++ b/arch/arm/mach-sa1100/Kconfig	Sat Apr  3 19:38:57 2004
@@ -204,7 +204,7 @@
 	depends on ARCH_SA1100
 	help
 	  Say Y here if you are using the inhand electronics OmniMeter.  See
-	  <http://www.inhandelectronics.com/html/omni1.html> for details.
+	  <http://www.inhandelectronics.com/omnimeter.asp> for details.
 
 config SA1100_PANGOLIN
 	bool "Pangolin"
@@ -232,7 +232,7 @@
 	help
 	  Say Y here if you intend to build a kernel suitable to run on
 	  a Pruftechnik Digital Board. For more information see
-	  <http://www.pruftechnik.com>
+	  <http://www.pruftechnik.com/>
 
 config SA1100_SHANNON
 	bool "Shannon"
@@ -250,8 +250,8 @@
 	  Say Y here to support the Blazie Engineering `Sherman' StrongARM
 	  1110-based SBC, used primarily in assistance products for the
 	  visually impaired.  The company is now Freedom Scientific, with
-	  a website at <http://www.freedomscientific.com/index.html>. The
-	  Sherman product, however, appears to have been discontinued.
+	  a website at <http://www.freedomscientific.com/>. The Sherman
+	  product, however, appears to have been discontinued.
 
 config SA1100_SIMPAD
 	bool "Simpad"
@@ -262,7 +262,7 @@
 	  FLASH. The SL4 version got 64 MB RAM and 32 MB FLASH and a
 	  PCMCIA-Slot. The version for the Germany Telecom (DTAG) is the same
 	  like CL4 in additional it has a PCMCIA-Slot. For more information
-	  visit <http://www.my-siemens.com or www.siemens.ch>.
+	  visit <http://www.my-siemens.com/> or <http://www.siemens.ch/>.
 
 config SA1100_PFS168
 	bool "Tulsa"
@@ -280,7 +280,7 @@
 	help
 	  Say Y here if you are using a Visu Aide Intel(R) StrongARM(R)
 	  SA-1100 based Victor Digital Talking Book Reader.  See
-	  <http://www.visuaide.com/pagevictor.en.html> for information on
+	  <http://www.visuaide.com/products.html> for information on
 	  this system.
 
 config SA1100_XP860
diff -Nru a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c
--- a/arch/arm/mach-sa1100/adsbitsy.c	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/mach-sa1100/adsbitsy.c	Sat Apr  3 19:38:40 2004
@@ -47,6 +47,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa1111_dmamask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa1111_resources),
 	.resource	= sa1111_resources,
diff -Nru a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
--- a/arch/arm/mach-sa1100/badge4.c	Sat Apr  3 19:38:41 2004
+++ b/arch/arm/mach-sa1100/badge4.c	Sat Apr  3 19:38:41 2004
@@ -55,6 +55,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa1111_dmamask;
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa1111_resources),
 	.resource	= sa1111_resources,
diff -Nru a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
--- a/arch/arm/mach-sa1100/generic.c	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/mach-sa1100/generic.c	Sat Apr  3 19:38:42 2004
@@ -162,6 +162,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa11x0udc_dma_mask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa11x0udc_resources),
 	.resource	= sa11x0udc_resources,
@@ -212,6 +213,7 @@
 	.id		= 0,
 	.dev = {
 		.dma_mask = &sa11x0mcp_dma_mask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa11x0mcp_resources),
 	.resource	= sa11x0mcp_resources,
@@ -232,6 +234,7 @@
 	.id		= 0,
 	.dev = {
 		.dma_mask = &sa11x0ssp_dma_mask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa11x0ssp_resources),
 	.resource	= sa11x0ssp_resources,
@@ -253,6 +256,9 @@
 static struct platform_device sa11x0fb_device = {
 	.name		= "sa11x0-fb",
 	.id		= 0,
+	.dev = {
+		.coherent_dma_mask = 0xffffffff,
+	},
 	.num_resources	= ARRAY_SIZE(sa11x0fb_resources),
 	.resource	= sa11x0fb_resources,
 };
diff -Nru a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c
--- a/arch/arm/mach-sa1100/graphicsmaster.c	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/mach-sa1100/graphicsmaster.c	Sat Apr  3 19:38:43 2004
@@ -44,6 +44,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa1111_dmamask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa1111_resources),
 	.resource	= sa1111_resources,
diff -Nru a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
--- a/arch/arm/mach-sa1100/jornada720.c	Sat Apr  3 19:38:57 2004
+++ b/arch/arm/mach-sa1100/jornada720.c	Sat Apr  3 19:38:57 2004
@@ -44,6 +44,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa1111_dmamask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa1111_resources),
 	.resource	= sa1111_resources,
diff -Nru a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
--- a/arch/arm/mach-sa1100/neponset.c	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/mach-sa1100/neponset.c	Sat Apr  3 19:38:43 2004
@@ -251,6 +251,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa1111_dmamask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa1111_resources),
 	.resource	= sa1111_resources,
diff -Nru a/arch/arm/mach-sa1100/pfs168.c b/arch/arm/mach-sa1100/pfs168.c
--- a/arch/arm/mach-sa1100/pfs168.c	Sat Apr  3 19:38:40 2004
+++ b/arch/arm/mach-sa1100/pfs168.c	Sat Apr  3 19:38:40 2004
@@ -38,6 +38,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa1111_dmamask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa1111_resources),
 	.resource	= sa1111_resources,
diff -Nru a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c
--- a/arch/arm/mach-sa1100/system3.c	Sat Apr  3 19:38:55 2004
+++ b/arch/arm/mach-sa1100/system3.c	Sat Apr  3 19:38:55 2004
@@ -393,6 +393,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa1111_dmamask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa1111_resources),
 	.resource	= sa1111_resources,
diff -Nru a/arch/arm/mach-sa1100/xp860.c b/arch/arm/mach-sa1100/xp860.c
--- a/arch/arm/mach-sa1100/xp860.c	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/mach-sa1100/xp860.c	Sat Apr  3 19:38:43 2004
@@ -45,6 +45,7 @@
 	.id		= 0,
 	.dev		= {
 		.dma_mask = &sa1111_dmamask,
+		.coherent_dma_mask = 0xffffffff,
 	},
 	.num_resources	= ARRAY_SIZE(sa1111_resources),
 	.resource	= sa1111_resources,
diff -Nru a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
--- a/arch/arm/mm/Kconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm/mm/Kconfig	Sat Apr  3 19:38:42 2004
@@ -185,8 +185,8 @@
 
 # SA110
 config CPU_SA110
-	bool "Support StrongARM(R) SA-110 processor" if !ARCH_EBSA110 && !FOOTBRIDGE && !ARCH_TBOX && !ARCH_SHARK && !ARCH_NEXUSPCI && !ARCH_ANAKIN && ARCH_RPC
-	default y if ARCH_EBSA110 || FOOTBRIDGE || ARCH_TBOX || ARCH_SHARK || ARCH_NEXUSPCI || ARCH_ANAKIN
+	bool "Support StrongARM(R) SA-110 processor" if !ARCH_EBSA110 && !FOOTBRIDGE && !ARCH_TBOX && !ARCH_SHARK && !ARCH_NEXUSPCI && ARCH_RPC
+	default y if ARCH_EBSA110 || FOOTBRIDGE || ARCH_TBOX || ARCH_SHARK || ARCH_NEXUSPCI
 	select CPU_32v3 if ARCH_RPC
 	select CPU_32v4 if !ARCH_RPC
 	select CPU_ABRT_EV4
diff -Nru a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
--- a/arch/arm/mm/consistent.c	Sat Apr  3 19:38:55 2004
+++ b/arch/arm/mm/consistent.c	Sat Apr  3 19:38:55 2004
@@ -76,34 +76,27 @@
 	.vm_end		= CONSISTENT_END,
 };
 
-#if 0
-static void vm_region_dump(struct vm_region *head, char *fn)
+static struct vm_region *
+vm_region_alloc(struct vm_region *head, size_t size, int gfp)
 {
-	struct vm_region *c;
+	unsigned long addr = head->vm_start, end = head->vm_end - size;
+	unsigned long flags;
+	struct vm_region *c, *new;
 
-	printk("Consistent Allocation Map (%s):\n", fn);
-	list_for_each_entry(c, &head->vm_list, vm_list) {
-		printk(" %p:  %08lx - %08lx   (0x%08x)\n", c,
-		       c->vm_start, c->vm_end, c->vm_end - c->vm_start);
-	}
-}
-#else
-#define vm_region_dump(head,fn)	do { } while(0)
-#endif
+	new = kmalloc(sizeof(struct vm_region), gfp);
+	if (!new)
+		goto out;
 
-static int vm_region_alloc(struct vm_region *head, struct vm_region *new, size_t size)
-{
-	unsigned long addr = head->vm_start, end = head->vm_end - size;
-	struct vm_region *c;
+	spin_lock_irqsave(&consistent_lock, flags);
 
 	list_for_each_entry(c, &head->vm_list, vm_list) {
 		if ((addr + size) < addr)
-			goto out;
+			goto nospc;
 		if ((addr + size) <= c->vm_start)
 			goto found;
 		addr = c->vm_end;
 		if (addr > end)
-			goto out;
+			goto nospc;
 	}
 
  found:
@@ -114,10 +107,14 @@
 	new->vm_start = addr;
 	new->vm_end = addr + size;
 
-	return 0;
+	spin_unlock_irqrestore(&consistent_lock, flags);
+	return new;
 
+ nospc:
+	spin_unlock_irqrestore(&consistent_lock, flags);
+	kfree(new);
  out:
-	return -ENOMEM;
+	return NULL;
 }
 
 static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
@@ -133,28 +130,46 @@
 	return c;
 }
 
-/*
- * This allocates one page of cache-coherent memory space and returns
- * both the virtual and a "dma" address to that space.
- */
-void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle,
-		       unsigned long cache_flags)
+#ifdef CONFIG_HUGETLB_PAGE
+#error ARM Coherent DMA allocator does not (yet) support huge TLB
+#endif
+
+static void *
+__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, int gfp,
+	    pgprot_t prot)
 {
 	struct page *page;
 	struct vm_region *c;
-	unsigned long order, flags;
-	void *ret = NULL;
-	int res;
+	unsigned long order;
+	u64 mask = 0x00ffffff, limit; /* ISA default */
 
 	if (!consistent_pte) {
-		printk(KERN_ERR "consistent_alloc: not initialised\n");
+		printk(KERN_ERR "%s: not initialised\n", __func__);
 		dump_stack();
 		return NULL;
 	}
 
+	if (dev) {
+		mask = dev->coherent_dma_mask;
+		if (mask == 0) {
+			dev_warn(dev, "coherent DMA mask is unset\n");
+			return NULL;
+		}
+	}
+
 	size = PAGE_ALIGN(size);
+	limit = (mask + 1) & ~mask;
+	if ((limit && size >= limit) || size >= (CONSISTENT_END - CONSISTENT_BASE)) {
+		printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n",
+		       size, mask);
+		return NULL;
+	}
+
 	order = get_order(size);
 
+	if (mask != 0xffffffff)
+		gfp |= GFP_DMA;
+
 	page = alloc_pages(gfp, order);
 	if (!page)
 		goto no_page;
@@ -165,36 +180,18 @@
 	 */
 	{
 		unsigned long kaddr = (unsigned long)page_address(page);
-		dmac_inv_range(kaddr, kaddr + size);
+		memset(page_address(page), 0, size);
+		dmac_flush_range(kaddr, kaddr + size);
 	}
 
 	/*
-	 * Our housekeeping doesn't need to come from DMA,
-	 * but it must not come from highmem.
-	 */
-	c = kmalloc(sizeof(struct vm_region),
-		    gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
-	if (!c)
-		goto no_remap;
-
-	/*
-	 * Attempt to allocate a virtual address in the
-	 * consistent mapping region.
+	 * Allocate a virtual address in the consistent mapping region.
 	 */
-	spin_lock_irqsave(&consistent_lock, flags);
-	vm_region_dump(&consistent_head, "before alloc");
-
-	res = vm_region_alloc(&consistent_head, c, size);
-
-	vm_region_dump(&consistent_head, "after alloc");
-	spin_unlock_irqrestore(&consistent_lock, flags);
-
-	if (!res) {
+	c = vm_region_alloc(&consistent_head, size,
+			    gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+	if (c) {
 		pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
 		struct page *end = page + (1 << order);
-		pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
-					 L_PTE_DIRTY | L_PTE_WRITE |
-					 cache_flags);
 
 		/*
 		 * Set the "dma handle"
@@ -220,38 +217,43 @@
 			page++;
 		}
 
-		ret = (void *)c->vm_start;
+		return (void *)c->vm_start;
 	}
 
- no_remap:
-	if (ret == NULL) {
-		kfree(c);
+	if (page)
 		__free_pages(page, order);
-	}
  no_page:
-	return ret;
+	return NULL;
 }
 
 /*
- * Since we have the DMA mask available to us here, we could try to do
- * a normal allocation, and only fall back to a "DMA" allocation if the
- * resulting bus address does not satisfy the dma_mask requirements.
+ * Allocate DMA-coherent memory space and return both the kernel remapped
+ * virtual and bus address for that space.
  */
 void *
 dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
 {
-	if (dev == NULL || *dev->dma_mask != 0xffffffff)
-		gfp |= GFP_DMA;
-
-	return consistent_alloc(gfp, size, handle, 0);
+	return __dma_alloc(dev, size, handle, gfp,
+			   pgprot_noncached(pgprot_kernel));
 }
-
 EXPORT_SYMBOL(dma_alloc_coherent);
 
 /*
+ * Allocate a writecombining region, in much the same way as
+ * dma_alloc_coherent above.
+ */
+void *
+dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
+{
+	return __dma_alloc(dev, size, handle, gfp,
+			   pgprot_writecombine(pgprot_kernel));
+}
+EXPORT_SYMBOL(dma_alloc_writecombine);
+
+/*
  * free a page as defined by the above mapping.
  */
-void consistent_free(void *vaddr, size_t size, dma_addr_t handle)
+void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle)
 {
 	struct vm_region *c;
 	unsigned long flags;
@@ -260,15 +262,14 @@
 	size = PAGE_ALIGN(size);
 
 	spin_lock_irqsave(&consistent_lock, flags);
-	vm_region_dump(&consistent_head, "before free");
 
-	c = vm_region_find(&consistent_head, (unsigned long)vaddr);
+	c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
 	if (!c)
 		goto no_area;
 
 	if ((c->vm_end - c->vm_start) != size) {
-		printk(KERN_ERR "consistent_free: wrong size (%ld != %d)\n",
-		       c->vm_end - c->vm_start, size);
+		printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n",
+		       __func__, c->vm_end - c->vm_start, size);
 		dump_stack();
 		size = c->vm_end - c->vm_start;
 	}
@@ -292,15 +293,14 @@
 			}
 		}
 
-		printk(KERN_CRIT "consistent_free: bad page in kernel page "
-		       "table\n");
+		printk(KERN_CRIT "%s: bad page in kernel page table\n",
+		       __func__);
 	} while (size -= PAGE_SIZE);
 
 	flush_tlb_kernel_range(c->vm_start, c->vm_end);
 
 	list_del(&c->vm_list);
 
-	vm_region_dump(&consistent_head, "after free");
 	spin_unlock_irqrestore(&consistent_lock, flags);
 
 	kfree(c);
@@ -308,10 +308,11 @@
 
  no_area:
 	spin_unlock_irqrestore(&consistent_lock, flags);
-	printk(KERN_ERR "consistent_free: trying to free "
-	       "invalid area: %p\n", vaddr);
+	printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n",
+	       __func__, cpu_addr);
 	dump_stack();
 }
+EXPORT_SYMBOL(dma_free_coherent);
 
 /*
  * Initialise the consistent memory allocation.
@@ -329,7 +330,7 @@
 		pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
 		pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
 		if (!pmd) {
-			printk(KERN_ERR "consistent_init: no pmd tables\n");
+			printk(KERN_ERR "%s: no pmd tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
@@ -337,7 +338,7 @@
 
 		pte = pte_alloc_kernel(&init_mm, pmd, CONSISTENT_BASE);
 		if (!pte) {
-			printk(KERN_ERR "consistent_init: no pte tables\n");
+			printk(KERN_ERR "%s: no pte tables\n", __func__);
 			ret = -ENOMEM;
 			break;
 		}
@@ -374,3 +375,4 @@
 		BUG();
 	}
 }
+EXPORT_SYMBOL(consistent_sync);
diff -Nru a/arch/arm/mm/fault-common.c b/arch/arm/mm/fault-common.c
--- a/arch/arm/mm/fault-common.c	Sat Apr  3 19:38:44 2004
+++ b/arch/arm/mm/fault-common.c	Sat Apr  3 19:38:44 2004
@@ -132,10 +132,12 @@
 	struct siginfo si;
 
 #ifdef CONFIG_DEBUG_USER
-	printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n",
-	       tsk->comm, addr, fsr);
-	show_pte(tsk->mm, addr);
-	show_regs(regs);
+	if (user_debug & UDBG_SEGV) {
+		printk(KERN_DEBUG "%s: unhandled page fault at 0x%08lx, code 0x%03x\n",
+		       tsk->comm, addr, fsr);
+		show_pte(tsk->mm, addr);
+		show_regs(regs);
+	}
 #endif
 
 	tsk->thread.address = addr;
@@ -296,8 +298,10 @@
 	tsk->thread.trap_no = 14;
 	force_sig(SIGBUS, tsk);
 #ifdef CONFIG_DEBUG_USER
-	printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n",
-		current->comm, addr, instruction_pointer(regs));
+	if (user_debug & UDBG_BUS) {
+		printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n",
+			current->comm, addr, instruction_pointer(regs));
+	}
 #endif
 
 	/* Kernel mode? Handle exceptions or die */
diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
--- a/arch/arm/tools/mach-types	Sat Apr  3 19:38:43 2004
+++ b/arch/arm/tools/mach-types	Sat Apr  3 19:38:43 2004
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Tue Feb 24 17:17:50 2004
+# Last update: Sat Mar 13 14:36:30 2004
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -474,3 +474,14 @@
 reciva_tt		MACH_RECIVA_TT		RECIVA_TT		464
 cstcb01			MACH_CSTCB01		CSTCB01			465
 cstcb1			MACH_CSTCB1		CSTCB1			466
+shadwell		MACH_SHADWELL		SHADWELL		467
+goepel263		MACH_GOEPEL263		GOEPEL263		468
+acq100			MACH_ACQ100		ACQ100			469
+mx1fs2			MACH_MX1FS2		MX1FS2			470
+hiptop_g1		MACH_HIPTOP_G1		HIPTOP_G1		471
+sparky			MACH_SPARKY		SPARKY			472
+ns9750			MACH_NS9750		NS9750			473
+phoenix			MACH_PHOENIX		PHOENIX			474
+vr1000			MACH_VR1000		VR1000			475
+deisterpxa		MACH_DEISTERPXA		DEISTERPXA		476
+bcm1160			MACH_BCM1160		BCM1160			477
diff -Nru a/arch/arm26/Kconfig b/arch/arm26/Kconfig
--- a/arch/arm26/Kconfig	Sat Apr  3 19:38:44 2004
+++ b/arch/arm26/Kconfig	Sat Apr  3 19:38:44 2004
@@ -198,11 +198,6 @@
 
 source "drivers/char/Kconfig"
 
-config KBDMOUSE
-	bool
-	depends on ARCH_ACORN && BUSMOUSE=y
-	default y
-
 source "drivers/media/Kconfig"
 
 source "fs/Kconfig"
diff -Nru a/arch/arm26/defconfig b/arch/arm26/defconfig
--- a/arch/arm26/defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/arm26/defconfig	Sat Apr  3 19:38:42 2004
@@ -164,8 +164,6 @@
 # CONFIG_SERIAL_8250_RSA is not set
 # CONFIG_ATOMWIDE_SERIAL is not set
 # CONFIG_DUALSP_SERIAL is not set
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
 # CONFIG_SERIAL_AMBA is not set
 # CONFIG_SERIAL_AMBA_CONSOLE is not set
 # CONFIG_SERIAL_CLPS711X is not set
@@ -185,9 +183,6 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
-# CONFIG_I2C_ELV is not set
-# CONFIG_I2C_VELLEMAN is not set
 CONFIG_I2C_ALGOPCF=y
 # CONFIG_I2C_ELEKTOR is not set
 CONFIG_I2C_CHARDEV=y
diff -Nru a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c
--- a/arch/arm26/kernel/sys_arm.c	Sat Apr  3 19:38:44 2004
+++ b/arch/arm26/kernel/sys_arm.c	Sat Apr  3 19:38:44 2004
@@ -101,7 +101,7 @@
 	struct mmap_arg_struct a;
 
 	if (copy_from_user(&a, arg, sizeof(a)))
-		goto out;;
+		goto out;
 
 	error = -EINVAL;
 	if (a.offset & ~PAGE_MASK)
diff -Nru a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
--- a/arch/cris/kernel/process.c	Sat Apr  3 19:38:44 2004
+++ b/arch/cris/kernel/process.c	Sat Apr  3 19:38:44 2004
@@ -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 -Nru a/arch/h8300/Kconfig b/arch/h8300/Kconfig
--- a/arch/h8300/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/arch/h8300/Kconfig	Sat Apr  3 19:38:54 2004
@@ -37,6 +37,10 @@
 	bool
 	default y
 
+config PCI
+	bool
+	default n
+
 source "init/Kconfig"
 
 menu "Processor type and features"
diff -Nru a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile
--- a/arch/h8300/kernel/Makefile	Sat Apr  3 19:38:44 2004
+++ b/arch/h8300/kernel/Makefile	Sat Apr  3 19:38:44 2004
@@ -4,7 +4,7 @@
 
 extra-y := vmlinux.lds.s
 
-obj-y := process.o traps.o ptrace.o \
+obj-y := process.o traps.o ptrace.o ints.o \
 	 sys_h8300.o time.o semaphore.o signal.o \
          setup.o h8300_ksyms.o gpio.o init_task.o \
          syscalls.o
diff -Nru a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/h8300/kernel/ints.c	Sat Apr  3 19:38:42 2004
@@ -0,0 +1,248 @@
+/*
+ * linux/arch/h8300/platform/h8300h/ints.c
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * Based on linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c
+ *
+ * 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.
+ *
+ * Copyright 1996 Roman Zippel
+ * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/bootmem.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/hardirq.h>
+#include <asm/errno.h>
+
+/*
+ * This structure has only 4 elements for speed reasons
+ */
+typedef struct irq_handler {
+	irqreturn_t (*handler)(int, void *, struct pt_regs *);
+	int         flags;
+	int         count;
+	void	    *dev_id;
+	const char  *devname;
+} irq_handler_t;
+
+static irq_handler_t *irq_list[NR_IRQS];
+static int use_kmalloc;
+
+extern unsigned long *interrupt_redirect_table;
+extern const int h8300_saved_vectors[];
+extern const unsigned long h8300_trap_table[];
+int h8300_enable_irq_pin(unsigned int irq);
+void h8300_disable_irq_pin(unsigned int irq);
+
+#define CPU_VECTOR ((unsigned long *)0x000000)
+#define ADDR_MASK (0xffffff)
+
+#if defined(CONFIG_RAMKERNEL)
+static unsigned long __init *get_vector_address(void)
+{
+	unsigned long *rom_vector = CPU_VECTOR;
+	unsigned long base,tmp;
+	int vec_no;
+
+	base = rom_vector[EXT_IRQ0] & ADDR_MASK;
+	
+	/* check romvector format */
+	for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) {
+		if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK))
+			return NULL;
+	}
+
+	/* ramvector base address */
+	base -= EXT_IRQ0*4;
+
+	/* writerble check */
+	tmp = ~(*(volatile unsigned long *)base);
+	(*(volatile unsigned long *)base) = tmp;
+	if ((*(volatile unsigned long *)base) != tmp)
+		return NULL;
+	return (unsigned long *)base;
+}
+#endif
+
+void __init init_IRQ(void)
+{
+#if defined(CONFIG_RAMKERNEL)
+	int i;
+	unsigned long *ramvec,*ramvec_p;
+	const unsigned long *trap_entry;
+	const int *saved_vector;
+
+	ramvec = get_vector_address();
+	if (ramvec == NULL)
+		panic("interrupt vector serup failed.");
+	else
+		printk("virtual vector at 0x%08lx\n",(unsigned long)ramvec);
+
+	/* create redirect table */
+	ramvec_p = ramvec;
+	trap_entry = h8300_trap_table;
+	saved_vector = h8300_saved_vectors;
+	for ( i = 0; i < NR_IRQS; i++) {
+		if (i == *saved_vector) {
+			ramvec_p++;
+			saved_vector++;
+		} else {
+			if ( i < NR_TRAPS ) {
+				if (*trap_entry)
+					*ramvec_p = VECTOR(*trap_entry);
+				ramvec_p++;
+				trap_entry++;
+			} else
+				*ramvec_p++ = REDIRECT(interrupt_entry);
+		}
+	}
+	interrupt_redirect_table = ramvec;
+#ifdef DUMP_VECTOR
+	ramvec_p = ramvec;
+	for (i = 0; i < NR_IRQS; i++) {
+		if ((i % 8) == 0)
+			printk("\n%p: ",ramvec_p);
+		printk("%p ",*ramvec_p);
+		ramvec_p++;
+	}
+	printk("\n");
+#endif
+#endif
+}
+
+int request_irq(unsigned int irq, 
+		irqreturn_t (*handler)(int, void *, struct pt_regs *),
+                unsigned long flags, const char *devname, void *dev_id)
+{
+	irq_handler_t *irq_handle;
+	if (irq < 0 || irq >= NR_IRQS) {
+		printk("Incorrect IRQ %d from %s\n", irq, devname);
+		return -EINVAL;
+	}
+	if (irq_list[irq] || (h8300_enable_irq_pin(irq) == -EBUSY))
+		return -EBUSY;
+
+	if (use_kmalloc)
+		irq_handle = (irq_handler_t *)kmalloc(sizeof(irq_handler_t), GFP_ATOMIC);
+	else {
+		/* use bootmem allocater */
+		irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t));
+		irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000);
+	}
+
+	if (irq_handle == NULL)
+		return -ENOMEM;
+
+	irq_handle->handler = handler;
+	irq_handle->flags   = flags;
+	irq_handle->count   = 0;
+	irq_handle->dev_id  = dev_id;
+	irq_handle->devname = devname;
+	irq_list[irq] = irq_handle;
+	return 0;
+}
+
+EXPORT_SYMBOL(request_irq);
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+	if (irq >= NR_IRQS) {
+		return;
+	}
+	if (!irq_list[irq] || irq_list[irq]->dev_id != dev_id)
+		printk("Removing probably wrong IRQ %d from %s\n",
+		       irq, irq_list[irq]->devname);
+	h8300_disable_irq_pin(irq);
+	if (((unsigned long)irq_list[irq] & 0x80000000) == 0) {
+		kfree(irq_list[irq]);
+		irq_list[irq] = NULL;
+	}
+}
+
+EXPORT_SYMBOL(free_irq);
+
+/*
+ * Do we need these probe functions on the m68k?
+ */
+unsigned long probe_irq_on (void)
+{
+	return 0;
+}
+
+EXPORT_SYMBOL(probe_irq_on);
+
+int probe_irq_off (unsigned long irqs)
+{
+	return 0;
+}
+
+EXPORT_SYMBOL(probe_irq_off);
+
+void enable_irq(unsigned int irq)
+{
+	if (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS))
+		IER_REGS |= 1 << (irq - EXT_IRQ0);
+}
+
+void disable_irq(unsigned int irq)
+{
+	if (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS))
+		IER_REGS &= ~(1 << (irq - EXT_IRQ0));
+}
+
+asmlinkage void process_int(int irq, struct pt_regs *fp)
+{
+	irq_enter();
+	h8300_clear_isr(irq);
+	if (irq >= NR_TRAPS && irq < NR_IRQS) {
+		if (irq_list[irq]) {
+			irq_list[irq]->handler(irq, irq_list[irq]->dev_id, fp);
+			irq_list[irq]->count++;
+			if (irq_list[irq]->flags & SA_SAMPLE_RANDOM)
+				add_interrupt_randomness(irq);
+		}
+	} else {
+		BUG();
+	}
+	irq_exit();
+}
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+	int i = *(loff_t *) v;
+
+	if ((i < NR_IRQS) && (irq_list[i]!=NULL)) {
+		seq_printf(p, "%3d: %10u ",i,irq_list[i]->count);
+		seq_printf(p, "%s\n", irq_list[i]->devname);
+	}
+
+	return 0;
+}
+
+void init_irq_proc(void)
+{
+}
+
+static int __init enable_kmalloc(void)
+{
+	use_kmalloc = 1;
+	return 0;
+}
+core_initcall(enable_kmalloc);
diff -Nru a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c
--- a/arch/h8300/kernel/setup.c	Sat Apr  3 19:38:41 2004
+++ b/arch/h8300/kernel/setup.c	Sat Apr  3 19:38:41 2004
@@ -135,7 +135,7 @@
 	init_mm.brk = (unsigned long) 0; 
 
 #if (defined(CONFIG_H8300H_SIM) || defined(CONFIG_H8S_SIM)) && defined(CONFIG_GDB_MAGICPRINT)
-	register_console(&gdb_console);
+	register_console((struct console *)&gdb_console);
 #endif
 
 	printk("\r\n\nuClinux " CPU "\n");
diff -Nru a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c
--- a/arch/h8300/kernel/sys_h8300.c	Sat Apr  3 19:38:55 2004
+++ b/arch/h8300/kernel/sys_h8300.c	Sat Apr  3 19:38:55 2004
@@ -260,11 +260,6 @@
 	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 -Nru a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
--- a/arch/h8300/kernel/syscalls.S	Sat Apr  3 19:38:42 2004
+++ b/arch/h8300/kernel/syscalls.S	Sat Apr  3 19:38:42 2004
@@ -116,7 +116,7 @@
 	.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 -Nru a/arch/h8300/mm/init.c b/arch/h8300/mm/init.c
--- a/arch/h8300/mm/init.c	Sat Apr  3 19:38:43 2004
+++ b/arch/h8300/mm/init.c	Sat Apr  3 19:38:43 2004
@@ -156,7 +156,7 @@
 	/* DAVIDM look at setup memory map generically with reserved area */
 	unsigned long tmp;
 	extern char _etext, _stext, _sdata, _ebss, __init_begin, __init_end;
-	extern unsigned char _ramend, _ramstart;
+	extern unsigned long  _ramend, _ramstart;
 	unsigned long len = &_ramend - &_ramstart;
 	unsigned long start_mem = memory_start; /* DAVIDM - these must start at end of kernel */
 	unsigned long end_mem   = memory_end; /* DAVIDM - this must not include kernel stack at top */
diff -Nru a/arch/h8300/platform/h8300h/Makefile b/arch/h8300/platform/h8300h/Makefile
--- a/arch/h8300/platform/h8300h/Makefile	Sat Apr  3 19:38:54 2004
+++ b/arch/h8300/platform/h8300h/Makefile	Sat Apr  3 19:38:54 2004
@@ -4,15 +4,5 @@
 # Reuse any files we can from the H8/300H
 #
 
-#VPATH := $(VPATH):$(BOARD)
+obj-y := entry.o ints_h8300h.o
 
-.S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -I. -c $< -o $*.o
-
-obj-y := entry.o ints.o
-
-$(BOARD)/crt0_$(MODEL).o: $(BOARD)/crt0_$(MODEL).S
-
-entry.o: entry.S
-
-ints.o: ints.c
diff -Nru a/arch/h8300/platform/h8300h/aki3068net/Makefile b/arch/h8300/platform/h8300h/aki3068net/Makefile
--- a/arch/h8300/platform/h8300h/aki3068net/Makefile	Sat Apr  3 19:38:43 2004
+++ b/arch/h8300/platform/h8300h/aki3068net/Makefile	Sat Apr  3 19:38:43 2004
@@ -4,8 +4,3 @@
 
 extra-y := crt0_ram.o
 obj-y := timer.o
-
-timer.o: timer.c
-
-clean:
-	rm -f *.[oa]
diff -Nru a/arch/h8300/platform/h8300h/generic/Makefile b/arch/h8300/platform/h8300h/generic/Makefile
--- a/arch/h8300/platform/h8300h/generic/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/h8300/platform/h8300h/generic/Makefile	Sat Apr  3 19:38:41 2004
@@ -4,6 +4,3 @@
 
 obj-y := timer.o
 extra-y =  crt0_$(MODEL).o
-
-clean:
-	rm -f *.[oa]
diff -Nru a/arch/h8300/platform/h8300h/generic/timer.c b/arch/h8300/platform/h8300h/generic/timer.c
--- a/arch/h8300/platform/h8300h/generic/timer.c	Sat Apr  3 19:38:42 2004
+++ b/arch/h8300/platform/h8300h/generic/timer.c	Sat Apr  3 19:38:42 2004
@@ -31,7 +31,7 @@
 #include <asm/regs306x.h>
 #define CMFA 6
 
-int platform_timer_setup(void (*timer_int)(int, void *, struct pt_regs *))
+int platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
 {
 	ctrl_outb(H8300_TIMER_COUNT_DATA,TCORA2);
 	ctrl_outb(0x00,_8TCSR2);
@@ -62,7 +62,7 @@
 #define GRA  0x00ffff6a
 #define GRB  0x00ffff6c
 
-int platform_timer_setup(void (*timer_int)(int, void *, struct pt_regs *))
+int platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
 {
 	*(unsigned short *)GRA= H8300_TIMER_COUNT_DATA;
 	*(unsigned short *)TCNT=0;
diff -Nru a/arch/h8300/platform/h8300h/h8max/Makefile b/arch/h8300/platform/h8300h/h8max/Makefile
--- a/arch/h8300/platform/h8300h/h8max/Makefile	Sat Apr  3 19:38:40 2004
+++ b/arch/h8300/platform/h8300h/h8max/Makefile	Sat Apr  3 19:38:40 2004
@@ -4,8 +4,3 @@
 
 extra-y := crt0_ram.o
 obj-y := timer.o
-
-timer.o: timer.c
-
-clean:
-	rm -f *.[oa]
diff -Nru a/arch/h8300/platform/h8300h/ints.c b/arch/h8300/platform/h8300h/ints.c
--- a/arch/h8300/platform/h8300h/ints.c	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,251 +0,0 @@
-/*
- * linux/arch/h8300/platform/h8300h/ints.c
- *
- * Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- * Based on linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.c
- *
- * 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.
- *
- * Copyright 1996 Roman Zippel
- * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/random.h>
-#include <linux/bootmem.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-#include <asm/io.h>
-#include <asm/setup.h>
-#include <asm/gpio.h>
-#include <asm/hardirq.h>
-#include <asm/regs306x.h>
-#include <asm/errno.h>
-
-/*
- * This structure has only 4 elements for speed reasons
- */
-typedef struct irq_handler {
-	irqreturn_t (*handler)(int, void *, struct pt_regs *);
-	int         flags;
-	int         count;
-	void	    *dev_id;
-	const char  *devname;
-} irq_handler_t;
-
-static irq_handler_t *irq_list[NR_IRQS];
-static int use_kmalloc;
-
-extern unsigned long *interrupt_redirect_table;
-
-#define CPU_VECTOR ((unsigned long *)0x000000)
-#define ADDR_MASK (0xffffff)
-
-static inline unsigned long *get_vector_address(void)
-{
-	unsigned long *rom_vector = CPU_VECTOR;
-	unsigned long base,tmp;
-	int vec_no;
-
-	base = rom_vector[EXT_IRQ0] & ADDR_MASK;
-	
-	/* check romvector format */
-	for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ5; vec_no++) {
-		if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK))
-			return NULL;
-	}
-
-	/* ramvector base address */
-	base -= EXT_IRQ0*4;
-
-	/* writerble check */
-	tmp = ~(*(volatile unsigned long *)base);
-	(*(volatile unsigned long *)base) = tmp;
-	if ((*(volatile unsigned long *)base) != tmp)
-		return NULL;
-	return (unsigned long *)base;
-}
-
-void __init init_IRQ(void)
-{
-#if defined(CONFIG_RAMKERNEL)
-	int i;
-	unsigned long *ramvec,*ramvec_p;
-	unsigned long break_vec;
-
-#if defined(CONFIG_GDB_DEBUG)
-	break_vec = ramvec[TRAP3_VEC];
-#else
-	break_vec = VECTOR(trace_break);
-#endif
-
-	ramvec = get_vector_address();
-	if (ramvec == NULL)
-		panic("interrupt vector serup failed.");
-	else
-		printk("virtual vector at 0x%08lx\n",(unsigned long)ramvec);
-
-	for (ramvec_p = ramvec, i = 0; i < NR_IRQS; i++)
-		*ramvec_p++ = REDIRECT(interrupt_entry);
-
-	ramvec[TRAP0_VEC] = VECTOR(system_call);
-	ramvec[TRAP3_VEC] = break_vec;
-	interrupt_redirect_table = ramvec;
-#ifdef DUMP_VECTOR
-	ramvec_p = interrupt_redirect_table;
-	for (i = 0; i < NR_IRQS; i++) {
-		if ((i % 8) == 0)
-			printk("\n%p: ",ramvec_p);
-		printk("%p ",*ramvec_p);
-		ramvec_p++;
-	}
-	printk("\n");
-#endif
-#endif
-}
-
-int request_irq(unsigned int irq, 
-		irqreturn_t (*handler)(int, void *, struct pt_regs *),
-                unsigned long flags, const char *devname, void *dev_id)
-{
-	irq_handler_t *irq_handle;
-	if (irq < 0 || irq >= NR_IRQS) {
-		printk("Incorrect IRQ %d from %s\n", irq, devname);
-		return -EINVAL;
-	}
-	if (irq_list[irq])
-		return -EBUSY;
-	if (irq >= EXT_IRQ0 && irq <= EXT_IRQ3) {
-		if (H8300_GPIO_RESERVE(H8300_GPIO_P8, 1 << (irq - EXT_IRQ0)) == 0)
-			return -EBUSY;
-		H8300_GPIO_DDR(H8300_GPIO_P8, (irq - EXT_IRQ0), 0);
-	}
-	if (irq >= EXT_IRQ4 && irq <= EXT_IRQ5) {
-		if (H8300_GPIO_RESERVE(H8300_GPIO_P9, 1 << (irq - EXT_IRQ0)) == 0)
-			return -EBUSY;
-		H8300_GPIO_DDR(H8300_GPIO_P9, (irq - EXT_IRQ0), 0);
-	}
-
-	if (use_kmalloc)
-		irq_handle = (irq_handler_t *)kmalloc(sizeof(irq_handler_t), GFP_ATOMIC);
-	else {
-		/* use bootmem allocater */
-		irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t));
-		irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000);
-	}
-
-	if (irq_handle == NULL)
-		return -ENOMEM;
-
-	irq_handle->handler = handler;
-	irq_handle->flags   = flags;
-	irq_handle->count   = 0;
-	irq_handle->dev_id  = dev_id;
-	irq_handle->devname = devname;
-	irq_list[irq] = irq_handle;
-	return 0;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
-	if (irq >= NR_IRQS) {
-		return;
-	}
-	if (!irq_list[irq] || irq_list[irq]->dev_id != dev_id)
-		printk("Removing probably wrong IRQ %d from %s\n",
-		       irq, irq_list[irq]->devname);
-	if (irq >= EXT_IRQ0 && irq <= EXT_IRQ5)
-		*(volatile unsigned char *)IER &= ~(1 << (irq - EXT_IRQ0));
-	if (((unsigned long)irq_list[irq] & 0x80000000) == 0) {
-		kfree(irq_list[irq]);
-		irq_list[irq] = NULL;
-	}
-}
-
-EXPORT_SYMBOL(free_irq);
-
-/*
- * Do we need these probe functions on the m68k?
- */
-unsigned long probe_irq_on (void)
-{
-	return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_on);
-
-int probe_irq_off (unsigned long irqs)
-{
-	return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_off);
-
-void enable_irq(unsigned int irq)
-{
-	if (irq >= EXT_IRQ0 && irq <= EXT_IRQ5) {
-		*(volatile unsigned char *)IER |= (1 << (irq - EXT_IRQ0));
-		*(volatile unsigned char *)ISR &= ~(1 << (irq - EXT_IRQ0));
-	}
-}
-
-void disable_irq(unsigned int irq)
-{
-	if (irq >= EXT_IRQ0 && irq <= EXT_IRQ5) {
-		*(volatile unsigned char *)IER &= ~(1 << (irq - EXT_IRQ0));
-	}
-}
-
-asmlinkage void process_int(int vec, struct pt_regs *fp)
-{
-	irq_enter();
-	if (vec >= EXT_IRQ0 && vec <= EXT_IRQ5)
-		*(volatile unsigned char *)ISR &= ~(1 << (vec - EXT_IRQ0));
-	if (vec < NR_IRQS) {
-		if (irq_list[vec]) {
-			irq_list[vec]->handler(vec, irq_list[vec]->dev_id, fp);
-			irq_list[vec]->count++;
-			if (irq_list[vec]->flags & SA_SAMPLE_RANDOM)
-				add_interrupt_randomness(vec);
-		}
-	} else {
-		BUG();
-	}
-	irq_exit();
-}
-
-int show_interrupts(struct seq_file *p, void *v)
-{
-	int i = *(loff_t *) v;
-
-	if ((i < NR_IRQS) && (irq_list[i]!=NULL)) {
-		seq_printf(p, "%3d: %10u ",i,irq_list[i]->count);
-		seq_printf(p, "%s\n", irq_list[i]->devname);
-	}
-
-	return 0;
-}
-
-void init_irq_proc(void)
-{
-}
-
-static int __init enable_kmalloc(void)
-{
-	use_kmalloc = 1;
-	return 0;
-}
-core_initcall(enable_kmalloc);
diff -Nru a/arch/h8300/platform/h8300h/ints_h8300h.c b/arch/h8300/platform/h8300h/ints_h8300h.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/h8300/platform/h8300h/ints_h8300h.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,86 @@
+/*
+ * linux/arch/h8300/platform/h8300h/ints_h8300h.c
+ * Interrupt handling CPU variants
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/regs306x.h>
+
+/* saved vector list */
+const int __initdata h8300_saved_vectors[]={
+#if defined(CONFIG_GDB_DEBUG)
+	TRAP3_VEC,
+#endif
+	-1
+};
+
+/* trap entry table */
+const unsigned long __initdata h8300_trap_table[NR_TRAPS]={
+	0,0,0,0,0,0,0,0,
+	(unsigned long)system_call,  /* TRAPA #0 */
+	0,0,
+	(unsigned long)trace_break,  /* TRAPA #3 */
+};
+
+int h8300_enable_irq_pin(unsigned int irq)
+{
+	int bitmask;
+	if (irq < EXT_IRQ0 || irq > EXT_IRQ5)
+		return 0;
+
+	/* initialize IRQ pin */
+	bitmask = 1 << (irq - EXT_IRQ0);
+	switch(irq) {
+	case EXT_IRQ0:
+	case EXT_IRQ1:
+	case EXT_IRQ2:
+	case EXT_IRQ3:
+		if (H8300_GPIO_RESERVE(H8300_GPIO_P8, bitmask) == 0)
+			return -EBUSY;
+		H8300_GPIO_DDR(H8300_GPIO_P8, bitmask, H8300_GPIO_INPUT);
+		break;
+	case EXT_IRQ4:
+	case EXT_IRQ5:
+		if (H8300_GPIO_RESERVE(H8300_GPIO_P9, bitmask) == 0)
+			return -EBUSY;
+		H8300_GPIO_DDR(H8300_GPIO_P9, bitmask, H8300_GPIO_INPUT);
+		break;
+	}
+
+	return 0;
+}
+
+void h8300_disable_irq_pin(unsigned int irq)
+{
+	int bitmask;
+	if (irq < EXT_IRQ0 || irq > EXT_IRQ5)
+		return;
+
+	/* disable interrupt & release IRQ pin */
+	bitmask = 1 << (irq - EXT_IRQ0);
+	switch(irq) {
+	case EXT_IRQ0:
+	case EXT_IRQ1:
+	case EXT_IRQ2:
+	case EXT_IRQ3:
+		*(volatile unsigned char *)IER &= ~bitmask;
+		H8300_GPIO_FREE(H8300_GPIO_P8, bitmask);
+		break ;
+	case EXT_IRQ4:
+	case EXT_IRQ5:
+		*(volatile unsigned char *)IER &= ~bitmask;
+		H8300_GPIO_FREE(H8300_GPIO_P9, bitmask);
+		break;
+	}
+}
diff -Nru a/arch/h8300/platform/h8s/Makefile b/arch/h8300/platform/h8s/Makefile
--- a/arch/h8300/platform/h8s/Makefile	Sat Apr  3 19:38:55 2004
+++ b/arch/h8300/platform/h8s/Makefile	Sat Apr  3 19:38:55 2004
@@ -4,15 +4,4 @@
 # Reuse any files we can from the H8S
 #
 
-#VPATH := $(VPATH):$(BOARD)
-
-.S.o:
-	$(CC) -D__ASSEMBLY__ $(AFLAGS) -I. -c $< -o $*.o
-
-obj-y := entry.o ints.o
-
-$(BOARD)/crt0_$(MODEL).o: $(BOARD)/crt0_$(MODEL).S
-
-entry.o: entry.S
-
-ints.o: ints.c
+obj-y := entry.o ints_h8s.o
diff -Nru a/arch/h8300/platform/h8s/edosk2674/Makefile b/arch/h8300/platform/h8s/edosk2674/Makefile
--- a/arch/h8300/platform/h8s/edosk2674/Makefile	Sat Apr  3 19:38:45 2004
+++ b/arch/h8300/platform/h8s/edosk2674/Makefile	Sat Apr  3 19:38:45 2004
@@ -2,10 +2,5 @@
 # Makefile for the linux kernel.
 #
 
-extra-y := crt0_ram.o
+extra-y := crt0_$(MODEL).o
 obj-y := timer.o
-
-timer.o: timer.c
-
-clean:
-	rm -f *.[oa]
diff -Nru a/arch/h8300/platform/h8s/generic/Makefile b/arch/h8300/platform/h8s/generic/Makefile
--- a/arch/h8300/platform/h8s/generic/Makefile	Sat Apr  3 19:38:43 2004
+++ b/arch/h8300/platform/h8s/generic/Makefile	Sat Apr  3 19:38:43 2004
@@ -4,8 +4,3 @@
 
 extra-y =  crt0_$(MODEL).o
 obj-y := timer.o
-
-timer.o: timer.c
-
-clean:
-	rm -f *.[oa]
diff -Nru a/arch/h8300/platform/h8s/ints_h8s.c b/arch/h8300/platform/h8s/ints_h8s.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/h8300/platform/h8s/ints_h8s.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/h8300/platform/h8s/ints_h8s.c
+ * Interrupt handling CPU variants
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <asm/regs267x.h>
+
+/* saved vector list */
+const int __initdata h8300_saved_vectors[]={
+#if defined(CONFIG_GDB_DEBUG)
+	TRACE_VEC,
+	TRAP3_VEC,
+#endif
+	-1
+};
+
+/* trap entry table */
+const unsigned long __initdata h8300_trap_table[NR_TRAPS]={
+	0,0,0,0,0,
+	(unsigned long)trace_break,  /* TRACE */
+	0,0,
+	(unsigned long)system_call,  /* TRAPA #0 */
+	0,0,0,0,0,0,0
+};
+
+/* IRQ pin assignment */
+struct irq_pins {
+	unsigned char port_no;
+	unsigned char bit_no;
+} __attribute__((aligned(1),packed));
+/* ISTR = 0 */
+const static struct irq_pins irq_assign_table0[16]={
+        {H8300_GPIO_P5,H8300_GPIO_B0},{H8300_GPIO_P5,H8300_GPIO_B1},
+	{H8300_GPIO_P5,H8300_GPIO_B2},{H8300_GPIO_P5,H8300_GPIO_B3},
+	{H8300_GPIO_P5,H8300_GPIO_B4},{H8300_GPIO_P5,H8300_GPIO_B5},
+	{H8300_GPIO_P5,H8300_GPIO_B6},{H8300_GPIO_P5,H8300_GPIO_B7},
+	{H8300_GPIO_P6,H8300_GPIO_B0},{H8300_GPIO_P6,H8300_GPIO_B1},
+	{H8300_GPIO_P6,H8300_GPIO_B2},{H8300_GPIO_P6,H8300_GPIO_B3},
+	{H8300_GPIO_P6,H8300_GPIO_B4},{H8300_GPIO_P6,H8300_GPIO_B5},
+	{H8300_GPIO_PF,H8300_GPIO_B1},{H8300_GPIO_PF,H8300_GPIO_B2},
+}; 
+/* ISTR = 1 */
+const static struct irq_pins irq_assign_table1[16]={
+	{H8300_GPIO_P8,H8300_GPIO_B0},{H8300_GPIO_P8,H8300_GPIO_B1},
+	{H8300_GPIO_P8,H8300_GPIO_B2},{H8300_GPIO_P8,H8300_GPIO_B3},
+	{H8300_GPIO_P8,H8300_GPIO_B4},{H8300_GPIO_P8,H8300_GPIO_B5},
+	{H8300_GPIO_PH,H8300_GPIO_B2},{H8300_GPIO_PH,H8300_GPIO_B3},
+	{H8300_GPIO_P2,H8300_GPIO_B0},{H8300_GPIO_P2,H8300_GPIO_B1},
+	{H8300_GPIO_P2,H8300_GPIO_B2},{H8300_GPIO_P2,H8300_GPIO_B3},
+	{H8300_GPIO_P2,H8300_GPIO_B4},{H8300_GPIO_P2,H8300_GPIO_B5},
+	{H8300_GPIO_P2,H8300_GPIO_B6},{H8300_GPIO_P2,H8300_GPIO_B7},
+};
+
+#define IRQ_GPIO_MAP(irqbit,port,bit)				  \
+do {								  \
+	if (*(volatile unsigned short *)ITSR & irqbit) {	  \
+		port = irq_assign_table1[irq - EXT_IRQ0].port_no; \
+		bit  = irq_assign_table1[irq - EXT_IRQ0].bit_no;  \
+	} else {						  \
+		port = irq_assign_table0[irq - EXT_IRQ0].port_no; \
+		bit  = irq_assign_table0[irq - EXT_IRQ0].bit_no;  \
+	}							  \
+} while(0)
+
+int h8300_enable_irq_pin(unsigned int irq)
+{
+	if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) {
+		unsigned short ptn = 1 << (irq - EXT_IRQ0);
+		unsigned int port_no,bit_no;
+		IRQ_GPIO_MAP(ptn,port_no,bit_no);
+		if (H8300_GPIO_RESERVE(port_no, bit_no) == 0)
+			return -EBUSY;                   /* pin already use */
+		H8300_GPIO_DDR(port_no, bit_no, H8300_GPIO_INPUT);
+		*(volatile unsigned short *)ISR &= ~ptn; /* ISR clear */
+	}		
+	return 0;
+}
+
+void h8300_disable_irq_pin(unsigned int irq)
+{
+	if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15) {
+		/* disable interrupt & release IRQ pin */
+		unsigned short ptn = 1 << (irq - EXT_IRQ0);
+		unsigned short port_no,bit_no;
+		*(volatile unsigned short *)ISR &= ~ptn;
+		*(volatile unsigned short *)IER &= ~ptn;
+		IRQ_GPIO_MAP(ptn,port_no,bit_no);
+		H8300_GPIO_FREE(port_no, bit_no);
+	}
+}
diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
--- a/arch/i386/Kconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/i386/Kconfig	Sat Apr  3 19:38:41 2004
@@ -269,9 +269,6 @@
 	  use of some extended instructions, and passes appropriate optimization
 	  flags to GCC.
 
-config MELAN
-	bool "Elan"
-
 config MCRUSOE
 	bool "Crusoe"
 	help
@@ -457,8 +454,8 @@
 	  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
 	  Management" code will be disabled if you say Y here.
 
-	  See also the <file:Documentation/smp.tex>,
-	  <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
+	  See also the <file:Documentation/smp.txt>,
+	  <file:Documentation/i386/IO-APIC.txt>,
 	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
 	  <http://www.tldp.org/docs.html#howto>.
 
@@ -552,7 +549,7 @@
 	  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
@@ -640,16 +637,7 @@
 	  with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
 	  /dev/cpu/31/cpuid.
 
-config EDD
-	tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)"
-	depends on EXPERIMENTAL
-	help
-	  Say Y or M here if you want to enable BIOS Enhanced Disk Drive
-	  Services real mode BIOS calls to determine which disk
-	  BIOS tries boot from.  This information is then exported via driverfs.
-
-	  This option is experimental, but believed to be safe,
-	  and most disk controller BIOS vendors do not yet implement this feature.
+source "drivers/firmware/Kconfig"
 
 choice
 	prompt "High Memory Support"
@@ -831,7 +819,7 @@
 	depends on SMP && X86_IO_APIC
 	default y
 	help
- 	  The defalut yes will allow the kernel to do irq load balancing.
+ 	  The default yes will allow the kernel to do irq load balancing.
 	  Saying no will keep the kernel from doing irq load balancing.
 
 config HAVE_DEC_LOCK
@@ -1058,9 +1046,6 @@
 	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 +1061,9 @@
 	  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 +1229,6 @@
 	  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
@@ -1348,7 +1325,7 @@
 
 config X86_TRAMPOLINE
 	bool
-	depends on SMP || X86_VISWS
+	depends on X86_SMP || (X86_VOYAGER && SMP)
 	default y
 
 config PC
diff -Nru a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/boot/edd.S	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,127 @@
+/*
+ * BIOS Enhanced Disk Drive support
+ * by Matt Domsch <Matt_Domsch@dell.com> October 2002
+ * conformant to T13 Committee www.t13.org
+ *   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/edd.h>
+
+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
+# Read the first sector of device 80h and store the 4-byte signature
+	movl	$0xFFFFFFFF, %eax
+	movl	%eax, (DISK80_SIG_BUFFER)	# assume failure
+	movb	$READ_SECTORS, %ah
+	movb	$1, %al				# read 1 sector
+	movb	$0x80, %dl			# from device 80
+	movb	$0, %dh				# at head 0
+	movw	$1, %cx				# cylinder 0, sector 0
+	pushw	%es
+	pushw	%ds
+	popw	%es
+	movw	$EDDBUF, %bx
+	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
+disk_sig_done:
+	popw	%es
+
+# Do the BIOS Enhanced Disk Drive calls
+# 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 boot_params at EDDBUF.  The first four bytes of which are
+# used to store the device number, interface support map and version
+# 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 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 boot_params stores
+# the number of BIOS devices which exist, up to EDDMAXNR.
+# In setup.c, copy_edd() stores both boot_params buffers away
+# for later use, as they would get overwritten otherwise.
+# This code is sensitive to the size of the structs in edd.h
+edd_start:
+						# %ds points to the bootsector
+       						# result buffer for fn48
+	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
+
+edd_check_ext:
+	movb	$CHECKEXTENSIONSPRESENT, %ah    # Function 41
+	movw	$EDDMAGIC1, %bx			# magic
+	int	$0x13				# make the call
+	jc	edd_done			# no more BIOS devices
+
+	cmpw	$EDDMAGIC2, %bx			# is magic right?
+	jne	edd_next			# nope, next...
+
+	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:
+	movw	$EDDPARMSIZE, %ds:(%si)		# put size
+	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?
+	jb	edd_check_ext			# keep looping
+
+edd_done:
+#endif
diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
--- a/arch/i386/boot/setup.S	Sat Apr  3 19:38:44 2004
+++ b/arch/i386/boot/setup.S	Sat Apr  3 19:38:44 2004
@@ -44,13 +44,6 @@
  *
  * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
  * by Robert Schwebel, December 2001 <robert@schwebel.de>
- *    
- * BIOS Enhanced Disk Drive support
- * by Matt Domsch <Matt_Domsch@dell.com> October 2002
- * conformant to T13 Committee www.t13.org
- *   projects 1572D, 1484D, 1386D, 1226DT
- * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
- *	and Andrew Wilks <Andrew_Wilks@dell.com> September 2003
  */
 
 #include <linux/config.h>
@@ -59,7 +52,6 @@
 #include <linux/compile.h>
 #include <asm/boot.h>
 #include <asm/e820.h>
-#include <asm/edd.h>    
 #include <asm/page.h>
 	
 /* Signature words to ensure LILO loaded us right */
@@ -579,88 +571,7 @@
 done_apm_bios:
 #endif
 
-#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
-# Read the first sector of device 80h and store the 4-byte signature
-	movl	$0xFFFFFFFF, %eax
-	movl	%eax, (DISK80_SIG_BUFFER)	# assume failure
-	movb	$READ_SECTORS, %ah
-	movb	$1, %al				# read 1 sector
-	movb	$0x80, %dl			# from device 80
-	movb	$0, %dh				# at head 0
-	movw	$1, %cx				# cylinder 0, sector 0
-	pushw	%es
-	pushw	%ds
-	popw	%es
-	movw	$EDDBUF, %bx
-	int	$0x13
-	jc	disk_sig_done
-	movl	(EDDBUF+MBR_SIG_OFFSET), %eax
-	movl	%eax, (DISK80_SIG_BUFFER)	# store success
-disk_sig_done:
-	popw	%es
-
-# Do the BIOS Enhanced Disk Drive calls
-# This consists of two calls:
-#    int 13h ah=41h "Check Extensions Present"
-#    int 13h ah=48h "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
-# 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
-# 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. 
-# This code is sensitive to the size of the structs in edd.h
-edd_start:  
-						# %ds points to the bootsector
-       						# result buffer for fn48
-    	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
-
-edd_check_ext:
-	movb	$CHECKEXTENSIONSPRESENT, %ah    # Function 41
-	movw	$EDDMAGIC1, %bx			# magic
-	int	$0x13				# make the call
-	jc	edd_done			# no more BIOS devices
-
-    	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
-	incb	(EDDNR)				# note that we stored something
-        
-edd_get_device_params:  
-	movw	$EDDPARMSIZE, %ds:(%si)		# put size
-    	movb	$GETDEVICEPARAMETERS, %ah	# Function 48
-	int	$0x13				# make the call
-						# Don't check for fail return
-						# it doesn't matter.
-	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?
-	jb	edd_check_ext			# keep looping
-    
-edd_done:   
-#endif
+#include "edd.S"
 
 # Now we want to move to protected mode ...
 	cmpw	$0, %cs:realmode_swtch
diff -Nru a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c
--- a/arch/i386/boot/tools/build.c	Sat Apr  3 19:38:43 2004
+++ b/arch/i386/boot/tools/build.c	Sat Apr  3 19:38:43 2004
@@ -150,10 +150,8 @@
 	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 -Nru a/arch/i386/defconfig b/arch/i386/defconfig
--- a/arch/i386/defconfig	Sat Apr  3 19:38:45 2004
+++ b/arch/i386/defconfig	Sat Apr  3 19:38:45 2004
@@ -66,7 +66,6 @@
 # CONFIG_MK6 is not set
 # CONFIG_MK7 is not set
 # CONFIG_MK8 is not set
-# CONFIG_MELAN is not set
 # CONFIG_MCRUSOE is not set
 # CONFIG_MWINCHIPC6 is not set
 # CONFIG_MWINCHIP2 is not set
@@ -101,6 +100,10 @@
 # CONFIG_MICROCODE is not set
 # CONFIG_X86_MSR is not set
 # CONFIG_X86_CPUID is not set
+
+#
+# Firmware Drivers
+#
 # CONFIG_EDD is not set
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
@@ -141,7 +144,6 @@
 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
 
 #
@@ -159,10 +161,12 @@
 #
 CONFIG_PCI=y
 # CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
 # CONFIG_PCI_GODIRECT is not set
 CONFIG_PCI_GOANY=y
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
 # CONFIG_PCI_USE_VECTOR is not set
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
@@ -239,8 +243,8 @@
 # CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
 CONFIG_LBD=y
 
 #
@@ -284,6 +288,7 @@
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_ATIIXP is not set
 # CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -306,7 +311,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -333,6 +337,12 @@
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
@@ -351,7 +361,9 @@
 # CONFIG_SCSI_SATA_SVW is not set
 CONFIG_SCSI_ATA_PIIX=y
 # CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_SIL is not set
 # CONFIG_SCSI_SATA_VIA is not set
+# CONFIG_SCSI_SATA_VITESSE is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -442,10 +454,6 @@
 # CONFIG_I2O is not set
 
 #
-# Macintosh device drivers
-#
-
-#
 # Networking support
 #
 CONFIG_NET=y
@@ -466,7 +474,6 @@
 # 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
@@ -536,7 +543,6 @@
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -657,6 +663,7 @@
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # Wan interfaces
@@ -677,6 +684,8 @@
 # Bluetooth support
 #
 # CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -723,6 +732,7 @@
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 CONFIG_INPUT_MOUSE=y
@@ -731,6 +741,7 @@
 # CONFIG_MOUSE_INPORT is not set
 # CONFIG_MOUSE_LOGIBM is not set
 # CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
@@ -763,11 +774,6 @@
 # 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
 
 #
@@ -821,6 +827,11 @@
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+# CONFIG_IBM_ASM is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -852,6 +863,9 @@
 # Advanced Linux Sound Architecture
 #
 CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_RAWMIDI=y
 CONFIG_SND_SEQUENCER=y
 # CONFIG_SND_SEQ_DUMMY is not set
 CONFIG_SND_OSSEMUL=y
@@ -864,6 +878,7 @@
 #
 # Generic devices
 #
+CONFIG_SND_MPU401_UART=y
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
@@ -899,13 +914,19 @@
 #
 # PCI devices
 #
+CONFIG_SND_AC97_CODEC=y
 # CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 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_MIXART is not set
 # CONFIG_SND_NM256 is not set
 # CONFIG_SND_RME32 is not set
 # CONFIG_SND_RME96 is not set
@@ -924,6 +945,7 @@
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 CONFIG_SND_INTEL8X0=y
+# CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_SONICVIBES is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VX222 is not set
@@ -955,6 +977,7 @@
 # USB Host Controller Drivers
 #
 CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
 # CONFIG_USB_OHCI_HCD is not set
 CONFIG_USB_UHCI_HCD=y
 
@@ -988,7 +1011,9 @@
 # CONFIG_USB_WACOM is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
 # CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
 
 #
 # USB Imaging devices
@@ -1034,7 +1059,6 @@
 # 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
@@ -1123,11 +1147,12 @@
 CONFIG_LOCKD=y
 CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # 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
 
 #
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/i386/kernel/Makefile	Sat Apr  3 19:38:41 2004
@@ -25,7 +25,6 @@
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_X86_SUMMIT_NUMA)	+= summit.o
-obj-$(CONFIG_EDD)             	+= edd.o
 obj-$(CONFIG_MODULES)		+= module.o
 obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
diff -Nru a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
--- a/arch/i386/kernel/acpi/boot.c	Sat Apr  3 19:38:55 2004
+++ b/arch/i386/kernel/acpi/boot.c	Sat Apr  3 19:38:55 2004
@@ -35,11 +35,21 @@
 #include <asm/irq.h>
 #include <asm/mpspec.h>
 
-#ifdef CONFIG_X86_LOCAL_APIC
+#ifdef	CONFIG_X86_64
+
+static inline void  acpi_madt_oem_check(char *oem_id, char *oem_table_id) { }
+static inline void clustered_apic_check(void) { }
+static inline int ioapic_setup_disabled(void) { return 0; }
+#include <asm/proto.h>
+
+#else	/* X86 */
+
+#ifdef	CONFIG_X86_LOCAL_APIC
 #include <mach_apic.h>
 #include <mach_mpparse.h>
-#include <asm/io_apic.h>
-#endif
+#endif	/* CONFIG_X86_LOCAL_APIC */
+
+#endif	/* X86 */
 
 #define PREFIX			"ACPI: "
 
@@ -50,10 +60,17 @@
 int acpi_ioapic;
 int acpi_strict;
 
+acpi_interrupt_flags acpi_sci_flags __initdata;
+int acpi_sci_override_gsi __initdata;
+
 #ifdef CONFIG_X86_LOCAL_APIC
 static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
 #endif
 
+#ifndef __HAVE_ARCH_CMPXCHG
+#warning ACPI uses CMPXCHG, i486 and later hardware
+#endif
+
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
@@ -64,6 +81,22 @@
  */
 enum acpi_irq_model_id		acpi_irq_model = ACPI_IRQ_MODEL_PIC;
 
+#ifdef	CONFIG_X86_64
+
+/* rely on all ACPI tables being in the direct mapping */
+char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
+{
+	if (!phys_addr || !size)
+	return NULL;
+
+	if (phys_addr < (end_pfn_map << PAGE_SHIFT))
+		return __va(phys_addr);
+
+	return NULL;
+}
+
+#else
+
 /*
  * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
  * to map the target physical address. The problem is that set_fixmap()
@@ -103,7 +136,7 @@
 
 	return ((unsigned char *) base + offset);
 }
-
+#endif
 
 #ifdef CONFIG_PCI_MMCONFIG
 static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
@@ -128,7 +161,9 @@
 
 	return 0;
 }
-#endif /* CONFIG_PCI_MMCONFIG */
+#else
+#define	acpi_parse_mcfg NULL
+#endif /* !CONFIG_PCI_MMCONFIG */
 
 #ifdef CONFIG_X86_LOCAL_APIC
 static int __init
@@ -242,6 +277,39 @@
 	return 0;
 }
 
+/*
+ * Parse Interrupt Source Override for the ACPI SCI
+ */
+static void
+acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
+{
+	if (trigger == 0)	/* compatible SCI trigger is level */
+		trigger = 3;
+
+	if (polarity == 0)	/* compatible SCI polarity is low */
+		polarity = 3;
+
+	/* Command-line over-ride via acpi_sci= */
+	if (acpi_sci_flags.trigger)
+		trigger = acpi_sci_flags.trigger;
+
+	if (acpi_sci_flags.polarity)
+		polarity = acpi_sci_flags.polarity;
+
+	/*
+ 	 * mp_config_acpi_legacy_irqs() already setup IRQs < 16
+	 * If GSI is < 16, this will update its flags,
+	 * else it will create a new mp_irqs[] entry.
+	 */
+	mp_override_legacy_irq(gsi, polarity, trigger, gsi);
+
+	/*
+	 * stash over-ride to indicate we've been here
+	 * and for later update of acpi_fadt
+	 */
+	acpi_sci_override_gsi = gsi;
+	return;
+}
 
 static int __init
 acpi_parse_int_src_ovr (
@@ -255,6 +323,12 @@
 
 	acpi_table_print_madt_entry(header);
 
+	if (intsrc->bus_irq == acpi_fadt.sci_int) {
+		acpi_sci_ioapic_setup(intsrc->global_irq,
+			intsrc->flags.polarity, intsrc->flags.trigger);
+		return 0;
+	}
+
 	mp_override_legacy_irq (
 		intsrc->bus_irq,
 		intsrc->flags.polarity,
@@ -285,14 +359,14 @@
 #endif /* CONFIG_X86_IO_APIC */
 
 #ifdef	CONFIG_ACPI_BUS
+
 /*
- * "acpi_pic_sci=level" (current default)
- * programs the PIC-mode SCI to Level Trigger.
- * (NO-OP if the BIOS set Level Trigger already)
+ * acpi_pic_sci_set_trigger()
+ * 
+ * use ELCR to set PIC-mode trigger type for SCI
  *
  * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
- * it may require Edge Trigger -- use "acpi_pic_sci=edge"
- * (NO-OP if the BIOS set Edge Trigger already)
+ * it may require Edge Trigger -- use "acpi_sci=edge"
  *
  * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
  * for the 8259 PIC.  bit[n] = 1 means irq[n] is Level, otherwise Edge.
@@ -300,10 +374,8 @@
  * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0)
  */
 
-static int __initdata	acpi_pic_sci_trigger;	/* 0: level, 1: edge */
-
 void __init
-acpi_pic_sci_set_trigger(unsigned int irq)
+acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
 {
 	unsigned char mask = 1 << (irq & 7);
 	unsigned int port = 0x4d0 + (irq >> 3);
@@ -314,41 +386,26 @@
 	if (!(val & mask)) {
 		printk(" Edge");
 
-		if (!acpi_pic_sci_trigger) {
+		if (trigger == 3) {
 			printk(" set to Level");
 			outb(val | mask, port);
 		}
 	} else {
 		printk(" Level");
 
-		if (acpi_pic_sci_trigger) {
+		if (trigger == 1) {
 			printk(" set to Edge");
-			outb(val | mask, port);
+			outb(val & ~mask, port);
 		}
 	}
 	printk(" Trigger.\n");
 }
 
-int __init
-acpi_pic_sci_setup(char *str)
-{
-	while (str && *str) {
-		if (strncmp(str, "level", 5) == 0)
-			acpi_pic_sci_trigger = 0;	/* force level trigger */
-		if (strncmp(str, "edge", 4) == 0)
-			acpi_pic_sci_trigger = 1;	/* force edge trigger */
-		str = strchr(str, ',');
-		if (str)
-			str += strspn(str, ", \t");
-	}
-	return 1;
-}
-
-__setup("acpi_pic_sci=", acpi_pic_sci_setup);
 
 #endif /* CONFIG_ACPI_BUS */
 
 #ifdef CONFIG_X86_IO_APIC
+/* deprecated in favor of acpi_gsi_to_irq */
 int acpi_irq_to_vector(u32 irq)
 {
 	if (use_pci_vector() && !platform_legacy_irq(irq))
@@ -357,6 +414,17 @@
 }
 #endif
 
+int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
+{
+#ifdef CONFIG_X86_IO_APIC
+	if (use_pci_vector() && !platform_legacy_irq(gsi))
+ 		*irq = IO_APIC_VECTOR(gsi);
+	else
+#endif
+		*irq = gsi;
+	return 0;
+}
+
 static unsigned long __init
 acpi_scan_rsdp (
 	unsigned long		start,
@@ -398,7 +466,6 @@
 
 
 #ifdef CONFIG_HPET_TIMER
-extern unsigned long hpet_address;
 
 static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
 {
@@ -419,16 +486,31 @@
 		return -1;
 	}
 
-	hpet_address = hpet_tbl->addr.addrl;
-	printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", hpet_tbl->id,
-	       hpet_address);
+#ifdef	CONFIG_X86_64
+        vxtime.hpet_address = hpet_tbl->addr.addrl |
+                ((long) hpet_tbl->addr.addrh << 32);
+
+        printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
+               hpet_tbl->id, vxtime.hpet_address);
+#else	/* X86 */
+	{
+		extern unsigned long hpet_address;
+
+		hpet_address = hpet_tbl->addr.addrl;
+		printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
+			hpet_tbl->id, hpet_address);
+	}
+#endif	/* X86 */
+
 	return 0;
 }
+#else
+#define	acpi_parse_hpet	NULL
 #endif
 
-/* detect the location of the ACPI PM Timer */
 #ifdef CONFIG_X86_PM_TIMER
 extern u32 pmtmr_ioport;
+#endif
 
 static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
 {
@@ -440,6 +522,13 @@
 		return 0;
 	}
 
+#ifdef	CONFIG_ACPI_INTERPRETER
+	/* initialize sci_int early for INT_SRC_OVR MADT parsing */
+	acpi_fadt.sci_int = fadt->sci_int;
+#endif
+
+#ifdef CONFIG_X86_PM_TIMER
+	/* detect the location of the ACPI PM Timer */
 	if (fadt->revision >= FADT2_REVISION_ID) {
 		/* FADT rev. 2 */
 		if (fadt->xpm_tmr_blk.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO)
@@ -452,9 +541,9 @@
 	}
 	if (pmtmr_ioport)
 		printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport);
+#endif
 	return 0;
 }
-#endif
 
 
 unsigned long __init
@@ -548,7 +637,7 @@
 	/*
  	 * if "noapic" boot option, don't look for IO-APICs
 	 */
-	if (ioapic_setup_disabled()) {
+	if (skip_ioapic_setup) {
 		printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
 			"due to 'noapic' option.\n");
 		return -ENODEV;
@@ -574,6 +663,13 @@
 		return count;
 	}
 
+	/*
+	 * If BIOS did not supply an INT_SRC_OVR for the SCI
+	 * pretend we got one so we can set the SCI flags.
+	 */
+	if (!acpi_sci_override_gsi)
+		acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
+
 	count = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS);
 	if (count < 0) {
 		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
@@ -662,11 +758,11 @@
 	 */
 	error = acpi_table_init();
 	if (error) {
-		acpi_disabled = 1;
+		disable_acpi();
 		return error;
 	}
 
-	(void) acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+	acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
 
 	/*
 	 * blacklist may disable ACPI entirely
@@ -674,28 +770,22 @@
 	error = acpi_blacklisted();
 	if (error) {
 		printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n");
-		acpi_disabled = 1;
+		disable_acpi();
 		return error;
 	}
 
 	/*
-	 * Process the Multiple APIC Description Table (MADT), if present
+	 * set sci_int and PM timer address
 	 */
-	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
+	/*
+	 * Process the Multiple APIC Description Table (MADT), if present
+	 */
+	acpi_process_madt();
 
-#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 -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c	Sat Apr  3 19:38:41 2004
+++ b/arch/i386/kernel/apm.c	Sat Apr  3 19:38:41 2004
@@ -1435,7 +1435,7 @@
 	return 0;
 }
 
-static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos)
+static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
 {
 	struct apm_user *	as;
 	int			i;
diff -Nru a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c
--- a/arch/i386/kernel/asm-offsets.c	Sat Apr  3 19:38:42 2004
+++ b/arch/i386/kernel/asm-offsets.c	Sat Apr  3 19:38:42 2004
@@ -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,6 @@
 
 	DEFINE(RT_SIGFRAME_sigcontext,
 	       offsetof (struct rt_sigframe, uc.uc_mcontext));
+
+	DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
 }
diff -Nru a/arch/i386/kernel/bootflag.c b/arch/i386/kernel/bootflag.c
--- a/arch/i386/kernel/bootflag.c	Sat Apr  3 19:38:54 2004
+++ b/arch/i386/kernel/bootflag.c	Sat Apr  3 19:38:54 2004
@@ -48,7 +48,7 @@
 		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 -Nru a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c
--- a/arch/i386/kernel/cpu/mcheck/mce.c	Sat Apr  3 19:38:54 2004
+++ b/arch/i386/kernel/cpu/mcheck/mce.c	Sat Apr  3 19:38:54 2004
@@ -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>
 
@@ -17,6 +18,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 -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	Sat Apr  3 19:38:42 2004
+++ b/arch/i386/kernel/dmi_scan.c	Sat Apr  3 19:38:42 2004
@@ -523,13 +523,13 @@
 
 
 #ifdef	CONFIG_ACPI_BOOT
-extern int acpi_disabled, acpi_force;
+extern int acpi_force;
 
-static __init __attribute__((unused)) int acpi_disable(struct dmi_blacklist *d) 
+static __init __attribute__((unused)) int dmi_disable_acpi(struct dmi_blacklist *d) 
 { 
 	if (!acpi_force) { 
 		printk(KERN_NOTICE "%s detected: acpi off\n",d->ident); 
-		acpi_disabled = 1;
+		disable_acpi();
 	} else { 
 		printk(KERN_NOTICE 
 		       "Warning: DMI blacklist says broken, but acpi forced\n"); 
@@ -537,8 +537,6 @@
 	return 0;
 } 
 
-extern int acpi_ht;
-
 /*
  * Limit ACPI to CPU enumeration for HT
  */
@@ -546,7 +544,7 @@
 { 
 	if (!acpi_force) { 
 		printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident); 
-		acpi_disabled = 1; 
+		disable_acpi();
 		acpi_ht = 1; 
 	} else { 
 		printk(KERN_NOTICE 
@@ -933,7 +931,7 @@
 	 *	Boxes that need ACPI disabled
 	 */
 
-	{ acpi_disable, "IBM Thinkpad", {
+	{ dmi_disable_acpi, "IBM Thinkpad", {
 			MATCH(DMI_BOARD_VENDOR, "IBM"),
 			MATCH(DMI_BOARD_NAME, "2629H1G"),
 			NO_MATCH, NO_MATCH }},
@@ -1063,8 +1061,7 @@
 			if (disable && !acpi_force) { 
 				printk(KERN_NOTICE "ACPI disabled because your bios is from %s and too old\n", s);
 				printk(KERN_NOTICE "You can enable it with acpi=force\n");
-				acpi_disabled = 1; 
-				acpi_ht = 0;
+				disable_acpi();
 			} 
 		}
 	}
diff -Nru a/arch/i386/kernel/edd.c b/arch/i386/kernel/edd.c
--- a/arch/i386/kernel/edd.c	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,761 +0,0 @@
-/*
- * linux/arch/i386/kernel/edd.c
- *  Copyright (C) 2002, 2003 Dell Inc.
- *  by Matt Domsch <Matt_Domsch@dell.com>
- *  disk80 signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
- *
- * BIOS Enhanced Disk Drive Services (EDD)
- * conformant to T13 Committee www.t13.org
- *   projects 1572D, 1484D, 1386D, 1226DT
- *
- * This code takes information provided by BIOS EDD calls
- * fn41 - Check Extensions Present and
- * fn48 - Get Device Parametes with EDD extensions
- * made in setup.S, copied to safe structures in setup.c,
- * and presents it in sysfs.
- *
- * Please see http://domsch.com/linux/edd30/results.html for
- * the list of BIOSs which have been reported to implement EDD.
- * If you don't see yours listed, please send a report as described there.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2.0 as published by
- * the Free Software Foundation
- *
- * 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.
- *
- */
-
-/*
- * Known issues:
- * - refcounting of struct device objects could be improved.
- *
- * TODO:
- * - Add IDE and USB disk device support
- * - move edd.[ch] to better locations if/when one is decided
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/stat.h>
-#include <linux/err.h>
-#include <linux/ctype.h>
-#include <linux/slab.h>
-#include <linux/limits.h>
-#include <linux/device.h>
-#include <linux/pci.h>
-#include <linux/device.h>
-#include <linux/blkdev.h>
-#include <asm/edd.h>
-/* FIXME - this really belongs in include/scsi/scsi.h */
-#include <../drivers/scsi/scsi.h>
-#include <../drivers/scsi/hosts.h>
-
-MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
-MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
-MODULE_LICENSE("GPL");
-
-#define EDD_VERSION "0.12 2004-Jan-26"
-#define EDD_DEVICE_NAME_SIZE 16
-#define REPORT_URL "http://linux.dell.com/edd/results.html"
-
-#define left (PAGE_SIZE - (p - buf) - 1)
-
-struct edd_device {
-	struct edd_info *info;
-	struct kobject kobj;
-};
-
-struct edd_attribute {
-	struct attribute attr;
-	ssize_t(*show) (struct edd_device * edev, char *buf);
-	int (*test) (struct edd_device * edev);
-};
-
-/* forward declarations */
-static int edd_dev_is_type(struct edd_device *edev, const char *type);
-static struct pci_dev *edd_get_pci_dev(struct edd_device *edev);
-
-static struct edd_device *edd_devices[EDDMAXNR];
-
-#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
-struct edd_attribute edd_attr_##_name = { 	\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.show	= _show,				\
-	.test	= _test,				\
-};
-
-static inline struct edd_info *
-edd_dev_get_info(struct edd_device *edev)
-{
-	return edev->info;
-}
-
-static inline void
-edd_dev_set_info(struct edd_device *edev, struct edd_info *info)
-{
-	edev->info = info;
-}
-
-#define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr)
-#define to_edd_device(obj) container_of(obj,struct edd_device,kobj)
-
-static ssize_t
-edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
-{
-	struct edd_device *dev = to_edd_device(kobj);
-	struct edd_attribute *edd_attr = to_edd_attr(attr);
-	ssize_t ret = 0;
-
-	if (edd_attr->show)
-		ret = edd_attr->show(dev, buf);
-	return ret;
-}
-
-static struct sysfs_ops edd_attr_ops = {
-	.show = edd_attr_show,
-};
-
-static ssize_t
-edd_show_host_bus(struct edd_device *edev, char *buf)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	char *p = buf;
-	int i;
-
-	if (!edev || !info || !buf) {
-		return -EINVAL;
-	}
-
-	for (i = 0; i < 4; i++) {
-		if (isprint(info->params.host_bus_type[i])) {
-			p += scnprintf(p, left, "%c", info->params.host_bus_type[i]);
-		} else {
-			p += scnprintf(p, left, " ");
-		}
-	}
-
-	if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
-		p += scnprintf(p, left, "\tbase_address: %x\n",
-			     info->params.interface_path.isa.base_address);
-	} else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
-		   !strncmp(info->params.host_bus_type, "PCI", 3)) {
-		p += scnprintf(p, left,
-			     "\t%02x:%02x.%d  channel: %u\n",
-			     info->params.interface_path.pci.bus,
-			     info->params.interface_path.pci.slot,
-			     info->params.interface_path.pci.function,
-			     info->params.interface_path.pci.channel);
-	} else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
-		   !strncmp(info->params.host_bus_type, "XPRS", 4) ||
-		   !strncmp(info->params.host_bus_type, "HTPT", 4)) {
-		p += scnprintf(p, left,
-			     "\tTBD: %llx\n",
-			     info->params.interface_path.ibnd.reserved);
-
-	} else {
-		p += scnprintf(p, left, "\tunknown: %llx\n",
-			     info->params.interface_path.unknown.reserved);
-	}
-	return (p - buf);
-}
-
-static ssize_t
-edd_show_interface(struct edd_device *edev, char *buf)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	char *p = buf;
-	int i;
-
-	if (!edev || !info || !buf) {
-		return -EINVAL;
-	}
-
-	for (i = 0; i < 8; i++) {
-		if (isprint(info->params.interface_type[i])) {
-			p += scnprintf(p, left, "%c", info->params.interface_type[i]);
-		} else {
-			p += scnprintf(p, left, " ");
-		}
-	}
-	if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
-		p += scnprintf(p, left, "\tdevice: %u  lun: %u\n",
-			     info->params.device_path.atapi.device,
-			     info->params.device_path.atapi.lun);
-	} else if (!strncmp(info->params.interface_type, "ATA", 3)) {
-		p += scnprintf(p, left, "\tdevice: %u\n",
-			     info->params.device_path.ata.device);
-	} else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
-		p += scnprintf(p, left, "\tid: %u  lun: %llu\n",
-			     info->params.device_path.scsi.id,
-			     info->params.device_path.scsi.lun);
-	} else if (!strncmp(info->params.interface_type, "USB", 3)) {
-		p += scnprintf(p, left, "\tserial_number: %llx\n",
-			     info->params.device_path.usb.serial_number);
-	} else if (!strncmp(info->params.interface_type, "1394", 4)) {
-		p += scnprintf(p, left, "\teui: %llx\n",
-			     info->params.device_path.i1394.eui);
-	} else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
-		p += scnprintf(p, left, "\twwid: %llx lun: %llx\n",
-			     info->params.device_path.fibre.wwid,
-			     info->params.device_path.fibre.lun);
-	} else if (!strncmp(info->params.interface_type, "I2O", 3)) {
-		p += scnprintf(p, left, "\tidentity_tag: %llx\n",
-			     info->params.device_path.i2o.identity_tag);
-	} else if (!strncmp(info->params.interface_type, "RAID", 4)) {
-		p += scnprintf(p, left, "\tidentity_tag: %x\n",
-			     info->params.device_path.raid.array_number);
-	} else if (!strncmp(info->params.interface_type, "SATA", 4)) {
-		p += scnprintf(p, left, "\tdevice: %u\n",
-			     info->params.device_path.sata.device);
-	} else {
-		p += scnprintf(p, left, "\tunknown: %llx %llx\n",
-			     info->params.device_path.unknown.reserved1,
-			     info->params.device_path.unknown.reserved2);
-	}
-
-	return (p - buf);
-}
-
-/**
- * edd_show_raw_data() - copies raw data to buffer for userspace to parse
- *
- * Returns: number of bytes written, or -EINVAL on failure
- */
-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;
-	if (!edev || !info || !buf) {
-		return -EINVAL;
-	}
-
-	if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
-		len = info->params.length;
-
-	/* In case of buggy BIOSs */
-	if (len > (sizeof(*info) - 4))
-		len = sizeof(*info) - 4;
-
-	memcpy(buf, ((char *)info) + 4, len);
-	return len;
-}
-
-static ssize_t
-edd_show_version(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 += scnprintf(p, left, "0x%02x\n", info->version);
-	return (p - buf);
-}
-
-static ssize_t
-edd_show_disk80_sig(struct edd_device *edev, char *buf)
-{
-	char *p = buf;
-	p += scnprintf(p, left, "0x%08x\n", edd_disk80_sig);
-	return (p - buf);
-}
-
-static ssize_t
-edd_show_extensions(struct edd_device *edev, char *buf)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	char *p = buf;
-	if (!edev || !info || !buf) {
-		return -EINVAL;
-	}
-
-	if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
-		p += scnprintf(p, left, "Fixed disk access\n");
-	}
-	if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
-		p += scnprintf(p, left, "Device locking and ejecting\n");
-	}
-	if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
-		p += scnprintf(p, left, "Enhanced Disk Drive support\n");
-	}
-	if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
-		p += scnprintf(p, left, "64-bit extensions\n");
-	}
-	return (p - buf);
-}
-
-static ssize_t
-edd_show_info_flags(struct edd_device *edev, char *buf)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	char *p = buf;
-	if (!edev || !info || !buf) {
-		return -EINVAL;
-	}
-
-	if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
-		p += scnprintf(p, left, "DMA boundary error transparent\n");
-	if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
-		p += scnprintf(p, left, "geometry valid\n");
-	if (info->params.info_flags & EDD_INFO_REMOVABLE)
-		p += scnprintf(p, left, "removable\n");
-	if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
-		p += scnprintf(p, left, "write verify\n");
-	if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
-		p += scnprintf(p, left, "media change notification\n");
-	if (info->params.info_flags & EDD_INFO_LOCKABLE)
-		p += scnprintf(p, left, "lockable\n");
-	if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
-		p += scnprintf(p, left, "no media present\n");
-	if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
-		p += scnprintf(p, left, "use int13 fn50\n");
-	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);
-	char *p = buf;
-	if (!edev || !info || !buf) {
-		return -EINVAL;
-	}
-
-	p += scnprintf(p, left, "0x%x\n", info->params.num_default_cylinders);
-	return (p - buf);
-}
-
-static ssize_t
-edd_show_default_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 += scnprintf(p, left, "0x%x\n", info->params.num_default_heads);
-	return (p - buf);
-}
-
-static ssize_t
-edd_show_default_sectors_per_track(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 += scnprintf(p, left, "0x%x\n", info->params.sectors_per_track);
-	return (p - buf);
-}
-
-static ssize_t
-edd_show_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 += scnprintf(p, left, "0x%llx\n", info->params.number_of_sectors);
-	return (p - buf);
-}
-
-
-/*
- * Some device instances may not have all the above attributes,
- * or the attribute values may be meaningless (i.e. if
- * the device is < EDD 3.0, it won't have host_bus and interface
- * information), so don't bother making files for them.  Likewise
- * if the default_{cylinders,heads,sectors_per_track} values
- * are zero, the BIOS doesn't provide sane values, don't bother
- * creating files for them either.
- */
-
-static int
-edd_has_default_cylinders(struct edd_device *edev)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	if (!edev || !info)
-		return -EINVAL;
-	return info->params.num_default_cylinders > 0;
-}
-
-static int
-edd_has_default_heads(struct edd_device *edev)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	if (!edev || !info)
-		return -EINVAL;
-	return info->params.num_default_heads > 0;
-}
-
-static int
-edd_has_default_sectors_per_track(struct edd_device *edev)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	if (!edev || !info)
-		return -EINVAL;
-	return info->params.sectors_per_track > 0;
-}
-
-static int
-edd_has_edd30(struct edd_device *edev)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	int i, nonzero_path = 0;
-	char c;
-
-	if (!edev || !info)
-		return 0;
-
-	if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
-		return 0;
-	}
-
-	for (i = 30; i <= 73; i++) {
-		c = *(((uint8_t *) info) + i + 4);
-		if (c) {
-			nonzero_path++;
-			break;
-		}
-	}
-	if (!nonzero_path) {
-		return 0;
-	}
-
-	return 1;
-}
-
-static int
-edd_has_disk80_sig(struct edd_device *edev)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-	if (!edev || !info)
-		return 0;
-	return info->device == 0x80;
-}
-
-static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, NULL);
-static EDD_DEVICE_ATTR(version, 0444, edd_show_version, NULL);
-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(default_cylinders, 0444, edd_show_default_cylinders,
-		       edd_has_default_cylinders);
-static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads,
-		       edd_has_default_heads);
-static EDD_DEVICE_ATTR(default_sectors_per_track, 0444,
-		       edd_show_default_sectors_per_track,
-		       edd_has_default_sectors_per_track);
-static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30);
-static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30);
-static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_disk80_sig, edd_has_disk80_sig);
-
-
-/* These are default attributes that are added for every edd
- * device discovered.
- */
-static struct attribute * def_attrs[] = {
-	&edd_attr_raw_data.attr,
-	&edd_attr_version.attr,
-	&edd_attr_extensions.attr,
-	&edd_attr_info_flags.attr,
-	&edd_attr_sectors.attr,
-	NULL,
-};
-
-/* These attributes are conditional and only added for some devices. */
-static struct edd_attribute * edd_attrs[] = {
-	&edd_attr_default_cylinders,
-	&edd_attr_default_heads,
-	&edd_attr_default_sectors_per_track,
-	&edd_attr_interface,
-	&edd_attr_host_bus,
-	&edd_attr_mbr_signature,
-	NULL,
-};
-
-/**
- *	edd_release - free edd structure
- *	@kobj:	kobject of edd structure
- *
- *	This is called when the refcount of the edd structure
- *	reaches 0. This should happen right after we unregister,
- *	but just in case, we use the release callback anyway.
- */
-
-static void edd_release(struct kobject * kobj)
-{
-	struct edd_device * dev = to_edd_device(kobj);
-	kfree(dev);
-}
-
-static struct kobj_type ktype_edd = {
-	.release	= edd_release,
-	.sysfs_ops	= &edd_attr_ops,
-	.default_attrs	= def_attrs,
-};
-
-static decl_subsys(edd,&ktype_edd,NULL);
-
-
-/**
- * edd_dev_is_type() - is this EDD device a 'type' device?
- * @edev
- * @type - a host bus or interface identifier string per the EDD spec
- *
- * Returns 1 (TRUE) if it is a 'type' device, 0 otherwise.
- */
-static int
-edd_dev_is_type(struct edd_device *edev, const char *type)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-
-	if (edev && type && info) {
-		if (!strncmp(info->params.host_bus_type, type, strlen(type)) ||
-		    !strncmp(info->params.interface_type, type, strlen(type)))
-			return 1;
-	}
-	return 0;
-}
-
-/**
- * edd_get_pci_dev() - finds pci_dev that matches edev
- * @edev - edd_device
- *
- * Returns pci_dev if found, or NULL
- */
-static struct pci_dev *
-edd_get_pci_dev(struct edd_device *edev)
-{
-	struct edd_info *info = edd_dev_get_info(edev);
-
-	if (edd_dev_is_type(edev, "PCI")) {
-		return pci_find_slot(info->params.interface_path.pci.bus,
-				     PCI_DEVFN(info->params.interface_path.pci.slot,
-					       info->params.interface_path.pci.
-					       function));
-	}
-	return NULL;
-}
-
-static int
-edd_create_symlink_to_pcidev(struct edd_device *edev)
-{
-
-	struct pci_dev *pci_dev = edd_get_pci_dev(edev);
-	if (!pci_dev)
-		return 1;
-	return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
-}
-
-/*
- * FIXME - as of 15-Jan-2003, there are some non-"scsi_device"s on the
- * scsi_bus list.  The following functions could possibly mis-access
- * memory in that case.  This is actually a problem with the SCSI
- * layer, which is being addressed there.  Until then, don't use the
- * SCSI functions.
- */
-
-#undef CONFIG_SCSI
-#undef CONFIG_SCSI_MODULE
-#if defined(CONFIG_SCSI) || defined(CONFIG_SCSI_MODULE)
-
-struct edd_match_data {
-	struct edd_device	* edev;
-	struct scsi_device	* sd;
-};
-
-/**
- * edd_match_scsidev()
- * @edev - EDD device is a known SCSI device
- * @sd - scsi_device with host who's parent is a PCI controller
- * 
- * returns 1 if a match is found, 0 if not.
- */
-static int edd_match_scsidev(struct device * dev, void * d)
-{
-	struct edd_match_data * data = (struct edd_match_data *)d;
-	struct edd_info *info = edd_dev_get_info(data->edev);
-	struct scsi_device * sd = to_scsi_device(dev);
-
-	if (info) {
-		if ((sd->channel == info->params.interface_path.pci.channel) &&
-		    (sd->id == info->params.device_path.scsi.id) &&
-		    (sd->lun == info->params.device_path.scsi.lun)) {
-			data->sd = sd;
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/**
- * edd_find_matching_device()
- * @edev - edd_device to match
- *
- * Search the SCSI devices for a drive that matches the EDD 
- * device descriptor we have. If we find a match, return it,
- * otherwise, return NULL.
- */
-
-static struct scsi_device *
-edd_find_matching_scsi_device(struct edd_device *edev)
-{
-	struct edd_match_data data;
-	struct bus_type * scsi_bus = find_bus("scsi");
-
-	if (!scsi_bus) {
-		return NULL;
-	}
-
-	data.edev = edev;
-
-	if (edd_dev_is_type(edev, "SCSI")) {
-		if (bus_for_each_dev(scsi_bus,NULL,&data,edd_match_scsidev))
-			return data.sd;
-	}
-	return NULL;
-}
-
-static int
-edd_create_symlink_to_scsidev(struct edd_device *edev)
-{
-	struct pci_dev *pci_dev;
-	int rc = -EINVAL;
-
-	pci_dev = edd_get_pci_dev(edev);
-	if (pci_dev) {
-		struct scsi_device * sdev = edd_find_matching_scsi_device(edev);
-		if (sdev && get_device(&sdev->sdev_driverfs_dev)) {
-			rc = sysfs_create_link(&edev->kobj,
-					       &sdev->sdev_driverfs_dev.kobj,
-					       "disc");
-			put_device(&sdev->sdev_driverfs_dev);
-		}
-	}
-	return rc;
-}
-
-#else
-static int
-edd_create_symlink_to_scsidev(struct edd_device *edev)
-{
-	return -ENOSYS;
-}
-#endif
-
-
-static inline void
-edd_device_unregister(struct edd_device *edev)
-{
-	kobject_unregister(&edev->kobj);
-}
-
-static void edd_populate_dir(struct edd_device * edev)
-{
-	struct edd_attribute * attr;
-	int error = 0;
-	int i;
-
-	for (i = 0; (attr = edd_attrs[i]) && !error; i++) {
-		if (!attr->test ||
-		    (attr->test && attr->test(edev)))
-			error = sysfs_create_file(&edev->kobj,&attr->attr);
-	}
-
-	if (!error) {
-		edd_create_symlink_to_pcidev(edev);
-		edd_create_symlink_to_scsidev(edev);
-	}
-}
-
-static int
-edd_device_register(struct edd_device *edev, int i)
-{
-	int error;
-
-	if (!edev)
-		return 1;
-	memset(edev, 0, sizeof (*edev));
-	edd_dev_set_info(edev, &edd[i]);
-	snprintf(edev->kobj.name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x",
-		 edd[i].device);
-	kobj_set_kset_s(edev,edd_subsys);
-	error = kobject_register(&edev->kobj);
-	if (!error)
-		edd_populate_dir(edev);
-	return error;
-}
-
-/**
- * edd_init() - creates sysfs tree of EDD data
- *
- * This assumes that eddnr and edd were
- * assigned in setup.c already.
- */
-static int __init
-edd_init(void)
-{
-	unsigned int i;
-	int rc=0;
-	struct edd_device *edev;
-
-	printk(KERN_INFO "BIOS EDD facility v%s, %d devices found\n",
-	       EDD_VERSION, eddnr);
-	printk(KERN_INFO "Please report your BIOS at %s\n", REPORT_URL);
-
-	if (!eddnr) {
-		printk(KERN_INFO "EDD information not available.\n");
-		return 1;
-	}
-
-	rc = firmware_register(&edd_subsys);
-	if (rc)
-		return rc;
-
-	for (i = 0; i < eddnr && i < EDDMAXNR && !rc; i++) {
-		edev = kmalloc(sizeof (*edev), GFP_KERNEL);
-		if (!edev)
-			return -ENOMEM;
-
-		rc = edd_device_register(edev, i);
-		if (rc) {
-			kfree(edev);
-			break;
-		}
-		edd_devices[i] = edev;
-	}
-
-	if (rc)
-		firmware_unregister(&edd_subsys);
-	return rc;
-}
-
-static void __exit
-edd_exit(void)
-{
-	int i;
-	struct edd_device *edev;
-
-	for (i = 0; i < eddnr && i < EDDMAXNR; i++) {
-		if ((edev = edd_devices[i]))
-			edd_device_unregister(edev);
-	}
-	firmware_unregister(&edd_subsys);
-}
-
-late_initcall(edd_init);
-module_exit(edd_exit);
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
--- a/arch/i386/kernel/head.S	Sat Apr  3 19:38:41 2004
+++ b/arch/i386/kernel/head.S	Sat Apr  3 19:38:41 2004
@@ -17,13 +17,8 @@
 #include <asm/desc.h>
 #include <asm/cache.h>
 #include <asm/thread_info.h>
-
-
-#define OLD_CL_MAGIC_ADDR	0x90020
-#define OLD_CL_MAGIC		0xA33F
-#define OLD_CL_BASE_ADDR	0x90000
-#define OLD_CL_OFFSET		0x90022
-#define NEW_CL_POINTER		0x228	/* Relative to real mode data */
+#include <asm/asm_offsets.h>
+#include <asm/setup.h>
 
 /*
  * References to members of the new_cpu_data structure.
@@ -40,49 +35,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
+
+/*
+ * 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
 
 /*
- * Set segments to known values
+ * 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 +134,40 @@
  *	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,38 +180,25 @@
 	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
- * is for the command line.
- *
+ * Copy bootup parameters out of the way.
  * Note: %esi still has the pointer to the real-mode data.
  */
-	movl $empty_zero_page,%edi
-	movl $512,%ecx
+	movl $boot_params,%edi
+	movl $(PARAM_SIZE/4),%ecx
 	cld
 	rep
 	movsl
-	xorl %eax,%eax
-	movl $512,%ecx
-	rep
-	stosl
-	movl empty_zero_page+NEW_CL_POINTER,%esi
+	movl boot_params+NEW_CL_POINTER,%esi
 	andl %esi,%esi
 	jnz 2f			# New command line protocol
 	cmpw $(OLD_CL_MAGIC),OLD_CL_MAGIC_ADDR
@@ -181,8 +206,8 @@
 	movzwl OLD_CL_OFFSET,%esi
 	addl $(OLD_CL_BASE_ADDR),%esi
 2:
-	movl $empty_zero_page+2048,%edi
-	movl $512,%ecx
+	movl $saved_command_line,%edi
+	movl $(COMMAND_LINE_SIZE/4),%ecx
 	rep
 	movsl
 1:
@@ -273,7 +298,7 @@
 	call initialize_secondary
 	jmp L6
 1:
-#endif
+#endif /* CONFIG_SMP */
 	call start_kernel
 L6:
 	jmp L6			# main should never return here, but
@@ -309,6 +334,8 @@
  *  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 +359,7 @@
 
 /* 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 +371,13 @@
 	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 +392,17 @@
  * 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 +417,25 @@
 	.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 +450,19 @@
 .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 +509,3 @@
 #ifdef CONFIG_SMP
 	.fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */
 #endif
-
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Sat Apr  3 19:38:56 2004
+++ b/arch/i386/kernel/i386_ksyms.c	Sat Apr  3 19:38:56 2004
@@ -88,10 +88,6 @@
 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);
@@ -180,10 +176,13 @@
  
 #undef memcpy
 #undef memset
+#undef memcmp
 extern void * memset(void *,int,__kernel_size_t);
 extern void * memcpy(void *,const void *,__kernel_size_t);
+extern int memcmp(const void *,const void *,__kernel_size_t);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memcmp);
 
 #ifdef CONFIG_HAVE_DEC_LOCK
 EXPORT_SYMBOL(atomic_dec_and_lock);
diff -Nru a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
--- a/arch/i386/kernel/init_task.c	Sat Apr  3 19:38:56 2004
+++ b/arch/i386/kernel/init_task.c	Sat Apr  3 19:38:56 2004
@@ -20,7 +20,7 @@
 /*
  * 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..
  */
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Sat Apr  3 19:38:42 2004
+++ b/arch/i386/kernel/io_apic.c	Sat Apr  3 19:38:42 2004
@@ -2440,7 +2440,11 @@
 	entry.polarity = active_high_low;
 	entry.mask  = 1;
 
-	add_pin_to_irq(irq, ioapic, pin);
+	/*
+	 * IRQs < 16 are already in the irq_2_pin[] map
+	 */
+	if (irq >= 16)
+		add_pin_to_irq(irq, ioapic, pin);
 
 	entry.vector = assign_irq_vector(irq);
 
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Sat Apr  3 19:38:42 2004
+++ b/arch/i386/kernel/mpparse.c	Sat Apr  3 19:38:42 2004
@@ -1,5 +1,5 @@
 /*
- *	Intel Multiprocessor Specificiation 1.1 and 1.4
+ *	Intel Multiprocessor Specification 1.1 and 1.4
  *	compliant MP-table parsing routines.
  *
  *	(c) 1995 Alan Cox, Building #3 <alan@redhat.com>
@@ -37,6 +37,7 @@
 
 /* Have we found an MP table */
 int smp_found_config;
+unsigned int __initdata maxcpus = NR_CPUS;
 
 /*
  * Various Linux-internal data structures created from the
@@ -168,8 +169,14 @@
 	}
 
 	if (num_processors >= NR_CPUS) {
-		printk(KERN_WARNING "NR_CPUS limit of %i reached.  Cannot "
-			"boot CPU(apicid 0x%x).\n", NR_CPUS, m->mpc_apicid);
+		printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
+			"  Processor ignored.\n", NR_CPUS); 
+		return;
+	}
+
+	if (num_processors >= maxcpus) {
+		printk(KERN_WARNING "WARNING: maxcpus limit of %i reached."
+			" Processor ignored.\n", maxcpus); 
 		return;
 	}
 	num_processors++;
@@ -844,25 +851,25 @@
 
 struct mp_ioapic_routing {
 	int			apic_id;
-	int			irq_start;
-	int			irq_end;
+	int			gsi_base;
+	int			gsi_end;
 	u32			pin_programmed[4];
 } mp_ioapic_routing[MAX_IO_APICS];
 
 
 static int __init mp_find_ioapic (
-	int			irq)
+	int			gsi)
 {
 	int			i = 0;
 
-	/* Find the IOAPIC that manages this IRQ. */
+	/* Find the IOAPIC that manages this GSI. */
 	for (i = 0; i < nr_ioapics; i++) {
-		if ((irq >= mp_ioapic_routing[i].irq_start)
-			&& (irq <= mp_ioapic_routing[i].irq_end))
+		if ((gsi >= mp_ioapic_routing[i].gsi_base)
+			&& (gsi <= mp_ioapic_routing[i].gsi_end))
 			return i;
 	}
 
-	printk(KERN_ERR "ERROR: Unable to locate IOAPIC for IRQ %d\n", irq);
+	printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
 
 	return -1;
 }
@@ -871,7 +878,7 @@
 void __init mp_register_ioapic (
 	u8			id, 
 	u32			address,
-	u32			irq_base)
+	u32			gsi_base)
 {
 	int			idx = 0;
 
@@ -897,19 +904,19 @@
 	mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
 	
 	/* 
-	 * Build basic IRQ lookup table to facilitate irq->io_apic lookups
-	 * and to prevent reprogramming of IOAPIC pins (PCI IRQs).
+	 * Build basic GSI lookup table to facilitate gsi->io_apic lookups
+	 * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
 	 */
 	mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid;
-	mp_ioapic_routing[idx].irq_start = irq_base;
-	mp_ioapic_routing[idx].irq_end = irq_base + 
+	mp_ioapic_routing[idx].gsi_base = gsi_base;
+	mp_ioapic_routing[idx].gsi_end = gsi_base + 
 		io_apic_get_redir_entries(idx);
 
 	printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%lx, "
-		"IRQ %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, 
+		"GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, 
 		mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
-		mp_ioapic_routing[idx].irq_start,
-		mp_ioapic_routing[idx].irq_end);
+		mp_ioapic_routing[idx].gsi_base,
+		mp_ioapic_routing[idx].gsi_end);
 
 	return;
 }
@@ -919,7 +926,7 @@
 	u8			bus_irq,
 	u8			polarity, 
 	u8			trigger, 
-	u32			global_irq)
+	u32			gsi)
 {
 	struct mpc_config_intsrc intsrc;
 	int			i = 0;
@@ -928,12 +935,12 @@
 	int			pin = -1;
 
 	/* 
-	 * Convert 'global_irq' to 'ioapic.pin'.
+	 * Convert 'gsi' to 'ioapic.pin'.
 	 */
-	ioapic = mp_find_ioapic(global_irq);
+	ioapic = mp_find_ioapic(gsi);
 	if (ioapic < 0)
 		return;
-	pin = global_irq - mp_ioapic_routing[ioapic].irq_start;
+	pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
 
 	/*
 	 * TBD: This check is for faulty timer entries, where the override
@@ -958,7 +965,7 @@
 
 	/* 
 	 * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it.
-	 * Otherwise create a new entry (e.g. global_irq == 2).
+	 * Otherwise create a new entry (e.g. gsi == 2).
 	 */
 	for (i = 0; i < mp_irq_entries; i++) {
 		if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) 
@@ -1029,69 +1036,6 @@
 
 extern FADT_DESCRIPTOR acpi_fadt;
 
-void __init mp_config_ioapic_for_sci(int irq)
-{
-	int ioapic;
-	int ioapic_pin;
-	struct acpi_table_madt *madt;
-	struct acpi_table_int_src_ovr *entry = NULL;
-	acpi_interrupt_flags flags;
-	void *madt_end;
-	acpi_status status;
-
-	/*
-	 * Ensure that if there is an interrupt source override entry
-	 * for the ACPI SCI, we leave it as is. Unfortunately this involves
-	 * walking the MADT again.
-	 */
-	status = acpi_get_firmware_table("APIC", 1, ACPI_LOGICAL_ADDRESSING,
-		(struct acpi_table_header **) &madt);
-	if (ACPI_SUCCESS(status)) {
-		madt_end = (void *) (unsigned long)madt + madt->header.length;
-
-		entry = (struct acpi_table_int_src_ovr *)
-                ((unsigned long) madt + sizeof(struct acpi_table_madt));
-
-		while ((void *) entry < madt_end) {
-                	if (entry->header.type == ACPI_MADT_INT_SRC_OVR &&
-			    acpi_fadt.sci_int == entry->bus_irq)
-				goto found;
-			
-                	entry = (struct acpi_table_int_src_ovr *)
-                	        ((unsigned long) entry + entry->header.length);
-        	}
-	}
-	/*
-	 * Although the ACPI spec says that the SCI should be level/low
-	 * don't reprogram it unless there is an explicit MADT OVR entry
-	 * instructing us to do so -- otherwise we break Tyan boards which
-	 * have the SCI wired edge/high but no MADT OVR.
-	 */
-	return;
-
-found:
-	/*
-	 * See the note at the end of ACPI 2.0b section
-	 * 5.2.10.8 for what this is about.
-	 */
-	flags = entry->flags;
-	acpi_fadt.sci_int = entry->global_irq;
-	irq = entry->global_irq;
-
-	ioapic = mp_find_ioapic(irq);
-
-	ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
-
-	/*
-	 * MPS INTI flags:
-	 *  trigger: 0=default, 1=edge, 3=level
-	 *  polarity: 0=default, 1=high, 3=low
-	 * Per ACPI spec, default for SCI means level/low.
-	 */
-	io_apic_set_pci_routing(ioapic, ioapic_pin, irq, 
-		(flags.trigger == 1 ? 0 : 1), (flags.polarity == 1 ? 0 : 1));
-}
-
 #ifdef CONFIG_ACPI_PCI
 
 void __init mp_parse_prt (void)
@@ -1100,7 +1044,7 @@
 	struct acpi_prt_entry	*entry = NULL;
 	int			ioapic = -1;
 	int			ioapic_pin = 0;
-	int			irq = 0;
+	int			gsi = 0;
 	int			idx, bit = 0;
 	int			edge_level = 0;
 	int			active_high_low = 0;
@@ -1112,39 +1056,39 @@
 	list_for_each(node, &acpi_prt.entries) {
 		entry = list_entry(node, struct acpi_prt_entry, node);
 
-		/* Need to get irq for dynamic entry */
+		/* Need to get gsi for dynamic entry */
 		if (entry->link.handle) {
-			irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
-			if (!irq)
+			gsi = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
+			if (!gsi)
 				continue;
 		}
 		else {
-			/* Hardwired IRQ. Assume PCI standard settings */
-			irq = entry->link.index;
+			/* Hardwired GSI. Assume PCI standard settings */
+			gsi = entry->link.index;
 			edge_level = 1;
 			active_high_low = 1;
 		}
 
 		/* Don't set up the ACPI SCI because it's already set up */
-                if (acpi_fadt.sci_int == irq) {
-			irq = acpi_irq_to_vector(irq);
-			entry->irq = irq; /* we still need to set entry's irq */
+                if (acpi_fadt.sci_int == gsi) {
+			/* we still need to set entry's irq */
+			acpi_gsi_to_irq(gsi, &entry->irq);
 			continue;
                 }
 	
-		ioapic = mp_find_ioapic(irq);
+		ioapic = mp_find_ioapic(gsi);
 		if (ioapic < 0)
 			continue;
-		ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
+		ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
 
 		if (es7000_plat) {
-			if (!ioapic && (irq < 16))
-				irq += 16;
+			if (!ioapic && (gsi < 16))
+				gsi += 16;
 		}
 
 		/* 
 		 * Avoid pin reprogramming.  PRTs typically include entries  
-		 * with redundant pin->irq mappings (but unique PCI devices);
+		 * with redundant pin->gsi mappings (but unique PCI devices);
 		 * we only only program the IOAPIC on the first.
 		 */
 		bit = ioapic_pin % 32;
@@ -1158,19 +1102,19 @@
 		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
 			Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
 				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
- 			entry->irq = acpi_irq_to_vector(irq);
+			acpi_gsi_to_irq(gsi, &entry->irq);
 			continue;
 		}
 
 		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
 
-		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low)) {
- 			entry->irq = acpi_irq_to_vector(irq);
- 		}
+		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
+			acpi_gsi_to_irq(gsi, &entry->irq);
+		}
 		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
-			entry->id.segment, entry->id.bus, 
-			entry->id.device, ('A' + entry->pin), 
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin, 
+			entry->id.segment, entry->id.bus,
+			entry->id.device, ('A' + entry->pin),
+			mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
 			entry->irq);
 	}
 
diff -Nru a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c
--- a/arch/i386/kernel/pci-dma.c	Sat Apr  3 19:38:42 2004
+++ b/arch/i386/kernel/pci-dma.c	Sat Apr  3 19:38:42 2004
@@ -20,8 +20,9 @@
 	/* 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 -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Sat Apr  3 19:38:31 2004
+++ b/arch/i386/kernel/process.c	Sat Apr  3 19:38:31 2004
@@ -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>
@@ -222,7 +223,7 @@
 
 	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",
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Sat Apr  3 19:38:43 2004
+++ b/arch/i386/kernel/setup.c	Sat Apr  3 19:38:43 2004
@@ -38,10 +38,10 @@
 #include <linux/module.h>
 #include <linux/efi.h>
 #include <linux/init.h>
+#include <linux/edd.h>
 #include <video/edid.h>
 #include <asm/e820.h>
 #include <asm/mpspec.h>
-#include <asm/edd.h>
 #include <asm/setup.h>
 #include <asm/arch_hooks.h>
 #include <asm/sections.h>
@@ -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);
@@ -78,8 +83,8 @@
 EXPORT_SYMBOL(acpi_disabled);
 
 #ifdef	CONFIG_ACPI_BOOT
-extern int __initdata acpi_ht;
 int __initdata acpi_force = 0;
+extern acpi_interrupt_flags	acpi_sci_flags;
 #endif
 
 int MCA_bus;
@@ -115,7 +120,6 @@
 extern void dmi_scan_machine(void);
 extern void generic_apic_probe(char *);
 extern int root_mountflags;
-extern char _end[];
 
 unsigned long saved_videomode;
 
@@ -126,6 +130,8 @@
 static char command_line[COMMAND_LINE_SIZE];
        char saved_command_line[COMMAND_LINE_SIZE];
 
+unsigned char __initdata boot_params[PARAM_SIZE];
+
 static struct resource code_resource = { "Kernel code", 0x100000, 0 };
 static struct resource data_resource = { "Kernel data", 0, 0 };
 
@@ -452,7 +458,7 @@
 #endif
 /**
  * copy_edd() - Copy the BIOS EDD information
- *              from empty_zero_page into a safe place.
+ *              from boot_params into a safe place.
  *
  */
 static inline void copy_edd(void)
@@ -481,12 +487,11 @@
 
 static void __init parse_cmdline_early (char ** cmdline_p)
 {
-	char c = ' ', *to = command_line, *from = COMMAND_LINE;
+	char c = ' ', *to = command_line, *from = saved_command_line;
 	int len = 0;
 	int userdef = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
-	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
 	saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
 
 	for (;;) {
@@ -555,17 +560,28 @@
 			}
 		}
 
+#ifdef  CONFIG_X86_SMP
+		/*
+		 * If the BIOS enumerates physical processors before logical,
+		 * maxcpus=N at enumeration-time can be used to disable HT.
+		 */
+		else if (!memcmp(from, "maxcpus=", 8)) {
+			extern unsigned int maxcpus;
+
+			maxcpus = simple_strtoul(from + 8, NULL, 0);
+		}
+#endif
+
 #ifdef CONFIG_ACPI_BOOT
 		/* "acpi=off" disables both ACPI table parsing and interpreter */
 		else if (!memcmp(from, "acpi=off", 8)) {
-			acpi_ht = 0;
-			acpi_disabled = 1;
+			disable_acpi();
 		}
 
 		/* acpi=force to over-ride black-list */
 		else if (!memcmp(from, "acpi=force", 10)) {
 			acpi_force = 1;
-			acpi_ht=1;
+			acpi_ht = 1;
 			acpi_disabled = 0;
 		}
 
@@ -576,8 +592,9 @@
 
 		/* Limit ACPI just to boot-time to enable HT */
 		else if (!memcmp(from, "acpi=ht", 7)) {
+			if (!acpi_force)
+				disable_acpi();
 			acpi_ht = 1;
-			if (!acpi_force) acpi_disabled = 1;
 		}
 
 		/* "pci=noacpi" disables ACPI interrupt routing */
@@ -585,6 +602,18 @@
 			acpi_noirq_set();
 		}
 
+		else if (!memcmp(from, "acpi_sci=edge", 13))
+			acpi_sci_flags.trigger =  1;
+
+		else if (!memcmp(from, "acpi_sci=level", 14))
+			acpi_sci_flags.trigger = 3;
+
+		else if (!memcmp(from, "acpi_sci=high", 13))
+			acpi_sci_flags.polarity = 1;
+
+		else if (!memcmp(from, "acpi_sci=low", 12))
+			acpi_sci_flags.polarity = 3;
+
 #ifdef CONFIG_X86_LOCAL_APIC
 		/* disable IO-APIC */
 		else if (!memcmp(from, "noapic", 6))
@@ -790,7 +819,7 @@
 	 * 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 +857,13 @@
 	 */
 	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 +1138,7 @@
 	init_mm.start_code = (unsigned long) _text;
 	init_mm.end_code = (unsigned long) _etext;
 	init_mm.end_data = (unsigned long) _edata;
-	init_mm.brk = (unsigned long) _end;
+	init_mm.brk = init_pg_tables_end + PAGE_OFFSET;
 
 	code_resource.start = virt_to_phys(_text);
 	code_resource.end = virt_to_phys(_etext)-1;
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
--- a/arch/i386/kernel/timers/timer_tsc.c	Sat Apr  3 19:38:45 2004
+++ b/arch/i386/kernel/timers/timer_tsc.c	Sat Apr  3 19:38:45 2004
@@ -360,8 +360,9 @@
 		if (variable_tsc)
 			cpu_data[freq->cpu].loops_per_jiffy = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
 #ifndef CONFIG_SMP
-		if (use_tsc) {
+		if (cpu_khz)
 			cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
+		if (use_tsc) {
 			if (variable_tsc) {
 				fast_gettimeoffset_quotient = cpufreq_scale(fast_gettimeoffset_ref, freq->new, ref_freq);
 				set_cyc2ns_scale(cpu_khz/1000);
diff -Nru a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
--- a/arch/i386/kernel/trampoline.S	Sat Apr  3 19:38:43 2004
+++ b/arch/i386/kernel/trampoline.S	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	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 @@
 	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
+	# flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
+	ljmpl	$__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET)
 
-boot_idt:
-	.word	0			# idt limit = 0
-	.word	0, 0			# idt base = 0L
-
-#
-# 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 -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Sat Apr  3 19:38:41 2004
+++ b/arch/i386/kernel/traps.c	Sat Apr  3 19:38:41 2004
@@ -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>
@@ -175,9 +176,10 @@
 		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\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);
diff -Nru a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
--- a/arch/i386/kernel/vmlinux.lds.S	Sat Apr  3 19:38:41 2004
+++ b/arch/i386/kernel/vmlinux.lds.S	Sat Apr  3 19:38:41 2004
@@ -3,7 +3,8 @@
  */
 
 #include <asm-generic/vmlinux.lds.h>
-	
+#include <asm/thread_info.h>
+
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH(i386)
 ENTRY(startup_32)
@@ -48,7 +49,7 @@
 
   _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 */
@@ -105,9 +106,14 @@
 	
   __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/ : {
diff -Nru a/arch/i386/kernel/vsyscall-int80.S b/arch/i386/kernel/vsyscall-int80.S
--- a/arch/i386/kernel/vsyscall-int80.S	Sat Apr  3 19:38:55 2004
+++ b/arch/i386/kernel/vsyscall-int80.S	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/arch/i386/kernel/vsyscall-sigreturn.S b/arch/i386/kernel/vsyscall-sigreturn.S
--- a/arch/i386/kernel/vsyscall-sigreturn.S	Sat Apr  3 19:38:54 2004
+++ b/arch/i386/kernel/vsyscall-sigreturn.S	Sat Apr  3 19:38:54 2004
@@ -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 -Nru a/arch/i386/kernel/vsyscall-sysenter.S b/arch/i386/kernel/vsyscall-sysenter.S
--- a/arch/i386/kernel/vsyscall-sysenter.S	Sat Apr  3 19:38:43 2004
+++ b/arch/i386/kernel/vsyscall-sysenter.S	Sat Apr  3 19:38:43 2004
@@ -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
diff -Nru a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
--- a/arch/i386/lib/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/i386/lib/Makefile	Sat Apr  3 19:38:41 2004
@@ -9,4 +9,3 @@
 
 lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
 lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o
-lib-$(CONFIG_DEBUG_IOVIRT)  += iodebug.o
diff -Nru a/arch/i386/lib/iodebug.c b/arch/i386/lib/iodebug.c
--- a/arch/i386/lib/iodebug.c	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/arch/i386/mach-default/Makefile b/arch/i386/mach-default/Makefile
--- a/arch/i386/mach-default/Makefile	Sat Apr  3 19:38:42 2004
+++ b/arch/i386/mach-default/Makefile	Sat Apr  3 19:38:42 2004
@@ -2,6 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_CFLAGS	+= -I../kernel
-
 obj-y				:= setup.o topology.o
diff -Nru a/arch/i386/mach-es7000/Makefile b/arch/i386/mach-es7000/Makefile
--- a/arch/i386/mach-es7000/Makefile	Sat Apr  3 19:38:43 2004
+++ b/arch/i386/mach-es7000/Makefile	Sat Apr  3 19:38:43 2004
@@ -2,6 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_CFLAGS	+= -I../kernel
-
 obj-y		:= setup.o topology.o es7000.o
diff -Nru a/arch/i386/mach-pc9800/Makefile b/arch/i386/mach-pc9800/Makefile
--- a/arch/i386/mach-pc9800/Makefile	Sat Apr  3 19:38:55 2004
+++ b/arch/i386/mach-pc9800/Makefile	Sat Apr  3 19:38:55 2004
@@ -2,6 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_CFLAGS	+= -I../kernel
-
 obj-y				:= setup.o topology.o
diff -Nru a/arch/i386/mach-visws/Makefile b/arch/i386/mach-visws/Makefile
--- a/arch/i386/mach-visws/Makefile	Sat Apr  3 19:38:55 2004
+++ b/arch/i386/mach-visws/Makefile	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
--- a/arch/i386/mach-voyager/voyager_smp.c	Sat Apr  3 19:38:42 2004
+++ b/arch/i386/mach-voyager/voyager_smp.c	Sat Apr  3 19:38:42 2004
@@ -623,7 +623,9 @@
 		((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 -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
--- a/arch/i386/mm/discontig.c	Sat Apr  3 19:38:44 2004
+++ b/arch/i386/mm/discontig.c	Sat Apr  3 19:38:44 2004
@@ -66,7 +66,7 @@
 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 @@
 	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 -Nru a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
--- a/arch/i386/mm/hugetlbpage.c	Sat Apr  3 19:38:55 2004
+++ b/arch/i386/mm/hugetlbpage.c	Sat Apr  3 19:38:55 2004
@@ -527,6 +527,13 @@
 	return (size + ~HPAGE_MASK)/HPAGE_SIZE <= htlbpagemem;
 }
 
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+	return htlbzone_pages * (HPAGE_SIZE / PAGE_SIZE);
+}
+EXPORT_SYMBOL(hugetlb_total_pages);
+
 /*
  * We cannot handle pagefaults against hugetlb pages at all.  They cause
  * handle_mm_fault() to try to instantiate regular-sized pages in the
diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c	Sat Apr  3 19:38:54 2004
+++ b/arch/i386/mm/init.c	Sat Apr  3 19:38:54 2004
@@ -474,9 +474,6 @@
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 #endif
 
-	/* clear the zero-page */
-	memset(empty_zero_page, 0, PAGE_SIZE);
-
 	/* this will put all low memory onto the freelists */
 	totalram_pages += __free_all_bootmem();
 
diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig
--- a/arch/ia64/Kconfig	Sat Apr  3 19:38:56 2004
+++ b/arch/ia64/Kconfig	Sat Apr  3 19:38:56 2004
@@ -39,24 +39,6 @@
 	default y
 
 choice
-	prompt "Processor type"
-	default ITANIUM
-
-config ITANIUM
-	bool "Itanium"
-	help
-	  Select your IA-64 processor type.  The default is Itanium.
-	  This choice is safe for all IA-64 systems, but may not perform
-	  optimally on systems with, say, Itanium 2 or newer processors.
-
-config MCKINLEY
-	bool "Itanium 2"
-	help
-	  Select this to configure for an Itanium 2 (McKinley) processor.
-
-endchoice
-
-choice
 	prompt "System type"
 	default IA64_GENERIC
 
@@ -97,6 +79,24 @@
 endchoice
 
 choice
+	prompt "Processor type"
+	default ITANIUM
+
+config ITANIUM
+	bool "Itanium"
+	help
+	  Select your IA-64 processor type.  The default is Itanium.
+	  This choice is safe for all IA-64 systems, but may not perform
+	  optimally on systems with, say, Itanium 2 or newer processors.
+
+config MCKINLEY
+	bool "Itanium 2"
+	help
+	  Select this to configure for an Itanium 2 (McKinley) processor.
+
+endchoice
+
+choice
 	prompt "Kernel page size"
 	default IA64_PAGE_SIZE_16KB
 
@@ -129,52 +129,6 @@
 
 endchoice
 
-config ACPI
-	bool
-	depends on !IA64_HP_SIM
-	default y
-	help
-	  ACPI/OSPM support for Linux is currently under development. As such,
-	  this support is preliminary and EXPERIMENTAL.  Configuring ACPI
-	  support enables kernel interfaces that allow higher level software
-	  (OSPM) to manipulate ACPI defined hardware and software interfaces,
-	  including the evaluation of ACPI control methods.  If unsure, choose
-	  N here.  Note, this option will enlarge your kernel by about 120K.
-
-	  This support requires an ACPI compliant platform (hardware/firmware).
-	  If both ACPI and Advanced Power Management (APM) support are
-	  configured, whichever is loaded first shall be used.
-
-	  This code DOES NOT currently provide a complete OSPM implementation
-	  -- it has not yet reached APM's level of functionality.  When fully
-	  implemented, Linux ACPI/OSPM will provide a more robust functional
-	  replacement for legacy configuration and power management
-	  interfaces, including the Plug-and-Play BIOS specification (PnP
-	  BIOS), the Multi-Processor Specification (MPS), and the Advanced
-	  Power Management specification (APM).
-
-	  Linux support for ACPI/OSPM is based on Intel Corporation's ACPI
-	  Component Architecture (ACPI CA). The latest ACPI CA source code,
-	  documentation, debug builds, and implementation status information
-	  can be downloaded from:
-	  <http://developer.intel.com/technology/iapc/acpi/downloads.htm>.
-
-	  The ACPI Sourceforge project may also be of interest:
-	  <http://sf.net/projects/acpi/>
-
-config ACPI_INTERPRETER
-	bool
-	depends on !IA64_HP_SIM
-	default y
-
-config ACPI_KERNEL_CONFIG
-	bool
-	depends on !IA64_HP_SIM
-	default y
-	help
-	  If you say `Y' here, Linux's ACPI support will use the
-	  hardware-level system descriptions found on IA-64 systems.
-
 config IA64_BRL_EMU
 	bool
 	depends on ITANIUM
@@ -238,40 +192,12 @@
 	  or have huge holes in the physical address space for other reasons.
 	  See <file:Documentation/vm/numa> for more.
 
-config IA64_MCA
-	bool "Machine Check Abort"
-	default y if !IA64_HP_SIM
-	help
-	  Say Y here to enable machine check support for IA-64.  If you're
-	  unsure, answer Y.
-
 config IA64_CYCLONE
 	bool "Support Cyclone(EXA) Time Source"
 	help
 		Say Y here to enable support for IBM EXA Cyclone time source.
 		If you're unsure, answer N.
 
-config PM
-	bool "Power Management support"
-	depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1
-	default y
-	help
-	  "Power Management" means that parts of your computer are shut
-	  off or put into a power conserving "sleep" mode if they are not
-	  being used.  There are two competing standards for doing this: APM
-	  and ACPI.  If you want to use either one, say Y here and then also
-	  to the requisite support below.
-
-	  Power Management is most important for battery powered laptop
-	  computers; if you have a laptop, check out the Linux Laptop home
-	  page on the WWW at <http://www.linux-on-laptops.com/> and the
-	  Battery Powered Linux mini-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  Note that, even if you say N here, Linux on the x86 architecture
-	  will issue the hlt instruction if nothing is to be done, thereby
-	  sending the processor to sleep and saving power.
-
 config IOSAPIC
 	bool
 	depends on !IA64_HP_SIM
@@ -288,15 +214,6 @@
 	int
 	default "18"
 
-config IA64_PAL_IDLE
-	bool "Use PAL_HALT_LIGHT in idle loop"
-	help
-	  Say Y here to enable use of PAL_HALT_LIGHT in the cpu_idle loop.
-	  This allows the CPU to enter a low power state when idle.  You
-	  can enable CONFIG_IA64_PALINFO and check /proc/pal/cpu0/power_info
-	  to see the power consumption and latency for this state.  If you're
-	  unsure your firmware supports it, answer N.
-
 config SMP
 	bool "Symmetric multi-processing support"
 	help
@@ -389,10 +306,48 @@
 
 source "fs/Kconfig.binfmt"
 
+endmenu
+
+menu "Power management and ACPI"
+
+config PM
+	bool "Power Management support"
+	depends on IA64_GENERIC || IA64_DIG || IA64_HP_ZX1
+	default y
+	help
+	  "Power Management" means that parts of your computer are shut
+	  off or put into a power conserving "sleep" mode if they are not
+	  being used.  There are two competing standards for doing this: APM
+	  and ACPI.  If you want to use either one, say Y here and then also
+	  to the requisite support below.
+
+	  Power Management is most important for battery powered laptop
+	  computers; if you have a laptop, check out the Linux Laptop home
+	  page on the WWW at <http://www.linux-on-laptops.com/> and the
+	  Battery Powered Linux mini-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  Note that, even if you say N here, Linux on the x86 architecture
+	  will issue the hlt instruction if nothing is to be done, thereby
+	  sending the processor to sleep and saving power.
+
+config ACPI
+	bool
+	depends on !IA64_HP_SIM
+	default y
+
 if !IA64_HP_SIM
 
 source "drivers/acpi/Kconfig"
 
+endif
+
+endmenu
+
+if !IA64_HP_SIM
+
+menu "Bus options (PCI, PCMCIA)"
+
 config PCI
 	bool "PCI support"
 	help
@@ -416,93 +371,14 @@
 
 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 +492,11 @@
 	  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 SYSVIPC_COMPAT
+	bool
+	depends on COMPAT && SYSVIPC
+	default y
 endmenu
 
 source "security/Kconfig"
diff -Nru a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig
--- a/arch/ia64/configs/generic_defconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/configs/generic_defconfig	Sat Apr  3 19:38:43 2004
@@ -105,7 +105,6 @@
 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
@@ -215,7 +214,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -239,7 +237,6 @@
 CONFIG_MD_RAID5=m
 CONFIG_MD_MULTIPATH=m
 CONFIG_BLK_DEV_DM=m
-CONFIG_DM_IOCTL_V4=y
 
 #
 # Fusion MPT device support
diff -Nru a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
--- a/arch/ia64/configs/sn2_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/ia64/configs/sn2_defconfig	Sat Apr  3 19:38:40 2004
@@ -17,6 +17,7 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=20
+CONFIG_HOTPLUG=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
@@ -30,7 +31,13 @@
 #
 # Loadable module support
 #
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
 
 #
 # Processor type and features
@@ -40,47 +47,49 @@
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_TIME_INTERPOLATION=y
-# CONFIG_ITANIUM is not set
-CONFIG_MCKINLEY=y
+CONFIG_EFI=y
 # CONFIG_IA64_GENERIC is not set
 # CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_HP_ZX1 is not set
 CONFIG_IA64_SGI_SN2=y
+# CONFIG_IA64_HP_SIM is not set
+# CONFIG_ITANIUM is not set
+CONFIG_MCKINLEY=y
 # 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=y
-CONFIG_DISCONTIGMEM=y
 CONFIG_VIRTUAL_MEM_MAP=y
-CONFIG_IA64_MCA=y
+CONFIG_DISCONTIGMEM=y
+# CONFIG_IA64_CYCLONE is not set
 CONFIG_IOSAPIC=y
-# CONFIG_IA64_SGI_SN_SIM is not set
+CONFIG_IA64_SGI_SN_SIM=y
 CONFIG_FORCE_MAX_ZONEORDER=18
-# CONFIG_IA64_PAL_IDLE is not set
 CONFIG_SMP=y
+CONFIG_NR_CPUS=512
 # CONFIG_PREEMPT is not set
+CONFIG_HAVE_DEC_LOCK=y
 CONFIG_IA32_SUPPORT=y
 CONFIG_COMPAT=y
-CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
-CONFIG_EFI=y
-# CONFIG_EFI_VARS is not set
-CONFIG_NR_CPUS=512
+CONFIG_EFI_VARS=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 
 #
+# Power management and ACPI
+#
+CONFIG_ACPI=y
+
+#
 # ACPI (Advanced Configuration and Power Interface) Support
 #
 CONFIG_ACPI_BOOT=y
+CONFIG_ACPI_INTERPRETER=y
 # CONFIG_ACPI_BUTTON is not set
 # CONFIG_ACPI_FAN is not set
 # CONFIG_ACPI_PROCESSOR is not set
@@ -90,17 +99,25 @@
 CONFIG_ACPI_POWER=y
 CONFIG_ACPI_PCI=y
 CONFIG_ACPI_SYSTEM=y
-# CONFIG_ACPI_RELAXED_AML is not set
+
+#
+# Bus options (PCI, PCMCIA)
+#
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
-CONFIG_HOTPLUG=y
 
 #
 # PCI Hotplug Support
 #
-# CONFIG_HOTPLUG_PCI is not set
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+CONFIG_HOTPLUG_PCI_SGI=y
 
 #
 # PCMCIA/CardBus support
@@ -108,14 +125,14 @@
 # CONFIG_PCMCIA is not set
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
 
 #
 # Generic Driver Options
 #
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -123,23 +140,28 @@
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # 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_DAC960=m
+CONFIG_BLK_DEV_UMEM=m
 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
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+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
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -150,21 +172,24 @@
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
-# CONFIG_BLK_DEV_IDEDISK is not set
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=m
 # 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 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
@@ -174,19 +199,20 @@
 # 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 is not set
+CONFIG_BLK_DEV_CMD64X=m
 # 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_HPT34X=m
+CONFIG_HPT34X_AUTODMA=y
+CONFIG_BLK_DEV_HPT366=m
 # 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_SVWKS=m
 CONFIG_BLK_DEV_SGIIOC4=y
 # CONFIG_BLK_DEV_SIIMAGE is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
@@ -195,30 +221,9 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
 # SCSI device support
 #
 CONFIG_SCSI=y
@@ -228,31 +233,57 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 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_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_REPORT_LUNS=y
-# CONFIG_SCSI_CONSTANTS is not set
+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
 # 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_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+CONFIG_SCSI_AIC7XXX_OLD=m
+CONFIG_SCSI_AIC79XX=m
+CONFIG_AIC79XX_CMDS_PER_DEVICE=32
+CONFIG_AIC79XX_RESET_DELAY_MS=15000
+# CONFIG_AIC79XX_BUILD_FIRMWARE is not set
+# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
+CONFIG_AIC79XX_DEBUG_ENABLE=y
+CONFIG_AIC79XX_DEBUG_MASK=0
+CONFIG_AIC79XX_REG_PRETTY_PRINT=y
 # CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_SATA is not set
+CONFIG_SCSI_MEGARAID=m
+CONFIG_SCSI_SATA=y
+CONFIG_SCSI_SATA_SVW=m
+CONFIG_SCSI_ATA_PIIX=m
+CONFIG_SCSI_SATA_PROMISE=m
+# CONFIG_SCSI_SATA_SIL is not set
+CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=y
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -262,16 +293,58 @@
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
+CONFIG_SCSI_SYM53C8XX_2=m
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_QLOGIC_ISP 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=y
+CONFIG_SCSI_QLA2300=y
+CONFIG_SCSI_QLA2322=y
+CONFIG_SCSI_QLA6312=y
+CONFIG_SCSI_QLA6322=y
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG 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_RAID6 is not set
+CONFIG_MD_MULTIPATH=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=m
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_MAX_SGE=40
+CONFIG_FUSION_ISENSE=m
+CONFIG_FUSION_CTL=m
+# CONFIG_FUSION_LAN is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -280,41 +353,131 @@
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
+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_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_FWMARK is not set
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
 # 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_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_NET_IPGRE_BROADCAST is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
 CONFIG_ARPD=y
-# CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 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=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
 # CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_PHYSDEV=m
+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=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# 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
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
 
 #
 # 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_VLAN_8021Q=m
 # 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_NET_DIVERT=y
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_FASTROUTE is not set
@@ -323,7 +486,31 @@
 #
 # QoS and/or fair queueing
 #
-# CONFIG_NET_SCHED is not set
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_DELAY is not set
+# CONFIG_NET_SCH_INGRESS is not set
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
 
 #
 # Network testing
@@ -335,38 +522,85 @@
 # 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
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
 # CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
-# CONFIG_NET_ETHERNET is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+# 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=m
+# 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
+# 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=m
+# CONFIG_EEPRO100_PIO 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 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 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_ACENIC=m
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+CONFIG_DL2K=m
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
+CONFIG_NS83820=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_R8169=m
+CONFIG_SIS190=m
+CONFIG_SK98LIN=m
 CONFIG_TIGON3=y
 
 #
 # Ethernet (10000 Mbit)
 #
-# CONFIG_IXGB is not set
+CONFIG_IXGB=m
+# CONFIG_IXGB_NAPI is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
 # CONFIG_SLIP is not set
 
 #
@@ -378,8 +612,9 @@
 # Token Ring devices
 #
 # CONFIG_TR is not set
-# CONFIG_NET_FC is not set
+CONFIG_NET_FC=y
 # CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # Wan interfaces
@@ -400,11 +635,20 @@
 # Bluetooth support
 #
 # CONFIG_BT is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -440,9 +684,13 @@
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
@@ -465,36 +713,21 @@
 #
 # Serial drivers
 #
-# CONFIG_SERIAL_8250 is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_HCDP=y
+CONFIG_SERIAL_8250_ACPI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
 # Non-8250 serial port support
 #
+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
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -507,7 +740,6 @@
 #
 # 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
@@ -519,7 +751,17 @@
 #
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
+CONFIG_RAW_DRIVER=m
+CONFIG_MAX_RAW_DEVS=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
 
 #
 # Multimedia devices
@@ -532,20 +774,60 @@
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=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 is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# 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_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_FS_POSIX_ACL=y
 CONFIG_XFS_FS=y
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_QUOTA is not set
-# CONFIG_XFS_POSIX_ACL is not set
+CONFIG_XFS_RT=y
+CONFIG_XFS_QUOTA=y
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTACTL=y
 CONFIG_AUTOFS_FS=y
 CONFIG_AUTOFS4_FS=y
 
@@ -553,9 +835,9 @@
 # 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
@@ -571,11 +853,10 @@
 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
-# CONFIG_HUGETLB_PAGE is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
 
 #
@@ -584,6 +865,7 @@
 # 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
@@ -609,8 +891,9 @@
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# CONFIG_SMB_FS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
@@ -633,7 +916,7 @@
 # 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_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
 CONFIG_EFI_PARTITION=y
@@ -682,32 +965,11 @@
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
 # Library routines
 #
 CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
 
 #
 # Profiling support
@@ -717,22 +979,19 @@
 #
 # Kernel hacking
 #
-# CONFIG_IA64_GRANULE_16MB is not set
-CONFIG_IA64_GRANULE_64MB=y
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_IA64_PRINT_HAZARDS is not set
 # CONFIG_DISABLE_VHPT is not set
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-# CONFIG_IA64_EARLY_PRINTK_UART is not set
-# CONFIG_IA64_EARLY_PRINTK_VGA is not set
-CONFIG_IA64_EARLY_PRINTK_SGI_SN=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
+CONFIG_SYSVIPC_COMPAT=y
 
 #
 # Security options
@@ -742,4 +1001,22 @@
 #
 # 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=m
+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_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_TEST is not set
diff -Nru a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ia64/configs/zx1_defconfig	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,1074 @@
+#
+# 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_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_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_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_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 -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig
--- a/arch/ia64/defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/ia64/defconfig	Sat Apr  3 19:38:41 2004
@@ -19,6 +19,7 @@
 CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=16
+CONFIG_HOTPLUG=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_EMBEDDED is not set
@@ -39,6 +40,7 @@
 CONFIG_OBSOLETE_MODPARM=y
 CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
 
 #
 # Processor type and features
@@ -49,37 +51,24 @@
 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_ITANIUM is not set
+CONFIG_MCKINLEY=y
 # 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 is not set
 CONFIG_SMP=y
 CONFIG_NR_CPUS=16
@@ -94,6 +83,14 @@
 CONFIG_BINFMT_MISC=y
 
 #
+# Power management and ACPI
+#
+CONFIG_PM=y
+CONFIG_ACPI=y
+CONFIG_ACPI_INTERPRETER=y
+CONFIG_ACPI_KERNEL_CONFIG=y
+
+#
 # ACPI (Advanced Configuration and Power Interface) Support
 #
 CONFIG_ACPI_BOOT=y
@@ -106,12 +103,14 @@
 CONFIG_ACPI_POWER=y
 CONFIG_ACPI_PCI=y
 CONFIG_ACPI_SYSTEM=y
-# CONFIG_ACPI_RELAXED_AML is not set
+
+#
+# Bus options (PCI, PCMCIA)
+#
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_LEGACY_PROC=y
 CONFIG_PCI_NAMES=y
-CONFIG_HOTPLUG=y
 
 #
 # PCI Hotplug Support
@@ -124,14 +123,14 @@
 # CONFIG_PCMCIA is not set
 
 #
-# Parallel port support
+# Device Drivers
 #
-# CONFIG_PARPORT is not set
 
 #
 # Generic Driver Options
 #
 # CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -139,6 +138,11 @@
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 
@@ -153,6 +157,7 @@
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
@@ -206,49 +211,16 @@
 # 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_SIIMAGE=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_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-
-#
-# Multi-device support (RAID and LVM)
-#
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=m
-CONFIG_MD_LINEAR=m
-CONFIG_MD_RAID0=m
-CONFIG_MD_RAID1=m
-CONFIG_MD_RAID5=m
-# CONFIG_MD_RAID6 is not set
-CONFIG_MD_MULTIPATH=m
-CONFIG_BLK_DEV_DM=m
-CONFIG_DM_IOCTL_V4=y
-
-#
-# Fusion MPT device support
-#
-CONFIG_FUSION=y
-CONFIG_FUSION_BOOT=y
-CONFIG_FUSION_MAX_SGE=40
-# CONFIG_FUSION_ISENSE is not set
-# CONFIG_FUSION_CTL is not set
-
-#
 # SCSI device support
 #
 CONFIG_SCSI=y
@@ -273,6 +245,12 @@
 CONFIG_SCSI_LOGGING=y
 
 #
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
@@ -316,6 +294,37 @@
 # CONFIG_SCSI_DEBUG is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+# CONFIG_MD_RAID6 is not set
+CONFIG_MD_MULTIPATH=m
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_CRYPT is not set
+
+#
+# Fusion MPT device support
+#
+CONFIG_FUSION=y
+CONFIG_FUSION_MAX_SGE=40
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -471,6 +480,7 @@
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # Wan interfaces
@@ -491,11 +501,18 @@
 # Bluetooth support
 #
 # CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -558,7 +575,8 @@
 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
@@ -576,7 +594,6 @@
 #
 # 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
@@ -601,172 +618,80 @@
 #
 # I2C support
 #
-# CONFIG_I2C 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
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
 
 #
-# DOS/FAT/NT Filesystems
+# I2C Algorithms
 #
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-# CONFIG_NTFS_FS is not set
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
 
 #
-# Pseudo filesystems
-#
-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=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_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
+# 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_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_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 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_LM80 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_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
 
 #
-# Network File Systems
+# Misc devices
 #
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_DIRECTIO=y
-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
+# Multimedia devices
 #
-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
+# CONFIG_VIDEO_DEV is not set
 
 #
-# Native Language Support
+# Digital Video Broadcasting Devices
 #
-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
+# CONFIG_DVB is not set
 
 #
 # Graphics support
@@ -780,6 +705,7 @@
 # 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 is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_ATY is not set
@@ -821,15 +747,23 @@
 # Advanced Linux Sound Architecture
 #
 CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
 CONFIG_SND_SEQUENCER=m
 # CONFIG_SND_SEQ_DUMMY is not set
-# CONFIG_SND_OSSEMUL is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_SEQUENCER_OSS is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
 #
 # Generic devices
 #
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
 # CONFIG_SND_DUMMY is not set
 # CONFIG_SND_VIRMIDI is not set
 # CONFIG_SND_MTPAV is not set
@@ -839,13 +773,19 @@
 #
 # PCI devices
 #
+CONFIG_SND_AC97_CODEC=m
 # CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 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_MIXART is not set
 # CONFIG_SND_NM256 is not set
 # CONFIG_SND_RME32 is not set
 # CONFIG_SND_RME96 is not set
@@ -861,9 +801,11 @@
 # CONFIG_SND_ES1968 is not set
 # CONFIG_SND_MAESTRO3 is not set
 CONFIG_SND_FM801=m
+# CONFIG_SND_FM801_TEA575X is not set
 # CONFIG_SND_ICE1712 is not set
 # CONFIG_SND_ICE1724 is not set
 # CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_SONICVIBES is not set
 # CONFIG_SND_VIA82XX is not set
 # CONFIG_SND_VX222 is not set
@@ -887,16 +829,16 @@
 #
 # Miscellaneous USB options
 #
-# CONFIG_USB_DEVICEFS is not set
+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_EHCI_HCD=y
 CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_UHCI_HCD=m
+CONFIG_USB_UHCI_HCD=y
 
 #
 # USB Device Class drivers
@@ -967,6 +909,7 @@
 # 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
@@ -974,6 +917,162 @@
 # CONFIG_USB_GADGET 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=y
+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_RPCSEC_GSS_KRB5=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
+
+#
 # Library routines
 #
 CONFIG_CRC32=y
@@ -990,7 +1089,7 @@
 # CONFIG_IA64_GRANULE_64MB is not set
 CONFIG_DEBUG_KERNEL=y
 CONFIG_IA64_PRINT_HAZARDS=y
-# CONFIG_DISABLE_VHPT is not set
+CONFIG_DISABLE_VHPT=y
 CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
@@ -998,6 +1097,7 @@
 # CONFIG_IA64_DEBUG_CMPXCHG is not set
 # CONFIG_IA64_DEBUG_IRQ is not set
 CONFIG_DEBUG_INFO=y
+CONFIG_SYSVIPC_COMPAT=y
 
 #
 # Security options
@@ -1007,4 +1107,21 @@
 #
 # Cryptographic options
 #
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+CONFIG_CRYPTO_DES=y
+# 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
diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
--- a/arch/ia64/hp/common/sba_iommu.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ia64/hp/common/sba_iommu.c	Sat Apr  3 19:38:41 2004
@@ -1055,13 +1055,13 @@
 	*dma_handle = virt_to_phys(addr);
 
 #ifdef ALLOW_IOV_BYPASS
-	ASSERT(to_pci_dev(dev)->consistent_dma_mask);
+	ASSERT(dev->coherent_dma_mask);
 	/*
  	** Check if the PCI device can DMA to ptr... if so, just return ptr
  	*/
-	if (likely((*dma_handle & ~to_pci_dev(dev)->consistent_dma_mask) == 0)) {
+	if (likely((*dma_handle & ~dev->coherent_dma_mask) == 0)) {
 		DBG_BYPASS("sba_alloc_coherent() bypass mask/addr: 0x%lx/0x%lx\n",
-		           to_pci_dev(dev)->consistent_dma_mask, *dma_handle);
+		           dev->coherent_dma_mask, *dma_handle);
 
 		return addr;
 	}
@@ -1479,7 +1479,6 @@
 #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 @@
 	/* 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 @@
 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;
-
-	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);
-	}
-}
+	/* 38 bit memory controller + extra bit for range displaced by MMIO */
+	ioc->dma_mask = (0x1UL << 39) - 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,7 @@
 
 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 },
+	{ SX1000_IOC_ID, "sx1000", NULL },
 };
 
 static struct ioc * __init
@@ -1718,11 +1703,6 @@
 	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 +1710,10 @@
 				(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 +1913,21 @@
 	 * 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;
@@ -1985,6 +1980,12 @@
 	return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL);
 }
 
+int
+sba_dma_mapping_error (dma_addr_t dma_addr)
+{
+	return 0;
+}
+
 __setup("nosbagart", nosbagart);
 
 static int __init
@@ -2010,6 +2011,7 @@
 
 __setup("sbapagesize=",sba_page_override);
 
+EXPORT_SYMBOL(sba_dma_mapping_error);
 EXPORT_SYMBOL(sba_map_single);
 EXPORT_SYMBOL(sba_unmap_single);
 EXPORT_SYMBOL(sba_map_sg);
diff -Nru a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
--- a/arch/ia64/hp/sim/simscsi.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/hp/sim/simscsi.c	Sat Apr  3 19:38:43 2004
@@ -8,23 +8,23 @@
  * 02/01/15 David Mosberger	Updated for v2.5.1
  * 99/12/18 David Mosberger	Added support for READ10/WRITE10 needed by linux v2.3.33
  */
-#include <linux/config.h>
 #include <linux/blkdev.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
-
-#include <scsi/scsi.h>
-
 #include <asm/irq.h>
 
-#include "../drivers/scsi/scsi.h"
-#include "../drivers/scsi/hosts.h"
-#include "simscsi.h"
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
 
 #define DEBUG_SIMSCSI	0
 
+#define SIMSCSI_REQ_QUEUE_LEN	64
+#define DEFAULT_SIMSCSI_ROOT	"/var/ski-disks/sd"
+
 /* Simulator system calls: */
 
 #define SSC_OPEN			50
@@ -47,7 +47,7 @@
 static struct Scsi_Host *host;
 
 static void simscsi_interrupt (unsigned long val);
-DECLARE_TASKLET(simscsi_tasklet, simscsi_interrupt, 0);
+static DECLARE_TASKLET(simscsi_tasklet, simscsi_interrupt, 0);
 
 struct disk_req {
 	unsigned long addr;
@@ -66,7 +66,7 @@
 };
 
 static struct queue_entry {
-	Scsi_Cmnd *sc;
+	struct scsi_cmnd *sc;
 } queue[SIMSCSI_REQ_QUEUE_LEN];
 
 static int rd, wr;
@@ -99,7 +99,7 @@
 static void
 simscsi_interrupt (unsigned long val)
 {
-	Scsi_Cmnd *sc;
+	struct scsi_cmnd *sc;
 
 	while ((sc = queue[rd].sc) != 0) {
 		atomic_dec(&num_reqs);
@@ -111,30 +111,7 @@
 	}
 }
 
-int
-simscsi_detect (Scsi_Host_Template *templ)
-{
-	templ->proc_name = "simscsi";
-	host = scsi_register(templ, 0);
-	if(host == NULL)
-		return 0;
-
-	return 1;	/* fake one SCSI host adapter */
-}
-
-int
-simscsi_release (struct Scsi_Host *host)
-{
-	return 0;	/* this is easy...  */
-}
-
-const char *
-simscsi_info (struct Scsi_Host *host)
-{
-	return "simulated SCSI host adapter";
-}
-
-int
+static int
 simscsi_biosparam (struct scsi_device *sdev, struct block_device *n,
 		sector_t capacity, int ip[])
 {
@@ -145,7 +122,7 @@
 }
 
 static void
-simscsi_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset, unsigned long len)
+simscsi_readwrite (struct scsi_cmnd *sc, int mode, unsigned long offset, unsigned long len)
 {
 	struct disk_stat stat;
 	struct disk_req req;
@@ -171,7 +148,7 @@
 }
 
 static void
-simscsi_sg_readwrite (Scsi_Cmnd *sc, int mode, unsigned long offset)
+simscsi_sg_readwrite (struct scsi_cmnd *sc, int mode, unsigned long offset)
 {
 	int list_len = sc->use_sg;
 	struct scatterlist *sl = (struct scatterlist *)sc->buffer;
@@ -208,7 +185,7 @@
  * Added 02/26/99 S.Eranian
  */
 static void
-simscsi_readwrite6 (Scsi_Cmnd *sc, int mode)
+simscsi_readwrite6 (struct scsi_cmnd *sc, int mode)
 {
 	unsigned long offset;
 
@@ -244,7 +221,7 @@
 }
 
 static void
-simscsi_readwrite10 (Scsi_Cmnd *sc, int mode)
+simscsi_readwrite10 (struct scsi_cmnd *sc, int mode)
 {
 	unsigned long offset;
 
@@ -256,8 +233,8 @@
 		simscsi_readwrite(sc, mode, offset, ((sc->cmnd[7] << 8) | sc->cmnd[8])*512);
 }
 
-int
-simscsi_queuecommand (Scsi_Cmnd *sc, void (*done)(Scsi_Cmnd *))
+static int
+simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
 {
 	unsigned int target_id = sc->device->id;
 	char fname[MAX_ROOT_LEN+16];
@@ -380,18 +357,16 @@
 	return 0;
 }
 
-int
-simscsi_host_reset (Scsi_Cmnd *sc)
+static int
+simscsi_host_reset (struct scsi_cmnd *sc)
 {
 	printk(KERN_ERR "simscsi_host_reset: not implemented\n");
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = {
-	.name			= "simscsi",
-	.detect			= simscsi_detect,
-	.release		= simscsi_release,
-	.info			= simscsi_info,	
+static struct scsi_host_template driver_template = {
+	.name			= "simulated SCSI host adapter",
+	.proc_name		= "simscsi",
 	.queuecommand		= simscsi_queuecommand,
 	.eh_host_reset_handler	= simscsi_host_reset,
 	.bios_param		= simscsi_biosparam,
@@ -402,4 +377,28 @@
 	.cmd_per_lun		= SIMSCSI_REQ_QUEUE_LEN,
 	.use_clustering		= DISABLE_CLUSTERING,
 };
-#include "../drivers/scsi/scsi_module.c"
+
+static int __init
+simscsi_init(void)
+{
+	int error;
+
+	host = scsi_host_alloc(&driver_template, 0);
+	if (!host)
+		return -ENOMEM;
+
+	error = scsi_add_host(host, NULL);
+	if (!error)
+		scsi_scan_host(host);
+	return error;
+}
+
+static void __exit
+simscsi_exit(void)
+{
+	scsi_remove_host(host);
+	scsi_host_put(host);
+}
+
+module_init(simscsi_init);
+module_exit(simscsi_exit);
diff -Nru a/arch/ia64/hp/sim/simscsi.h b/arch/ia64/hp/sim/simscsi.h
--- a/arch/ia64/hp/sim/simscsi.h	Sat Apr  3 19:38:40 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-/*
- * Simulated SCSI driver.
- *
- * Copyright (C) 1999, 2002 Hewlett-Packard Co
- *	David Mosberger-Tang <davidm@hpl.hp.com>
- */
-#ifndef SIMSCSI_H
-#define SIMSCSI_H
-
-#define SIMSCSI_REQ_QUEUE_LEN	64
-
-#define DEFAULT_SIMSCSI_ROOT	"/var/ski-disks/sd"
-
-extern int simscsi_detect (Scsi_Host_Template *);
-extern int simscsi_release (struct Scsi_Host *);
-extern const char *simscsi_info (struct Scsi_Host *);
-extern int simscsi_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int simscsi_abort (Scsi_Cmnd *);
-extern int simscsi_reset (Scsi_Cmnd *, unsigned int);
-extern int simscsi_biosparam (struct scsi_device *, struct block_device *,
-		sector_t, int[]);
-
-#endif /* SIMSCSI_H */
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- a/arch/ia64/hp/sim/simserial.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/hp/sim/simserial.c	Sat Apr  3 19:38:43 2004
@@ -636,7 +636,6 @@
 #ifdef SIMSERIAL_DEBUG
 		printk("rs_close: hung_up\n");
 #endif
-		MOD_DEC_USE_COUNT;
 		local_irq_restore(flags);
 		return;
 	}
@@ -661,7 +660,6 @@
 		state->count = 0;
 	}
 	if (state->count) {
-		MOD_DEC_USE_COUNT;
 		local_irq_restore(flags);
 		return;
 	}
@@ -686,7 +684,6 @@
 	}
 	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
-	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -874,17 +871,12 @@
 	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 @@
 
 	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 @@
 	    (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 @@
 	 */
 	retval = startup(info);
 	if (retval) {
-		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 		return retval;
 	}
 
@@ -1042,6 +1030,7 @@
 
 	/* 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 -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
--- a/arch/ia64/ia32/ia32_entry.S	Sat Apr  3 19:38:44 2004
+++ b/arch/ia64/ia32/ia32_entry.S	Sat Apr  3 19:38:44 2004
@@ -229,7 +229,7 @@
 	data8 sys_ni_syscall
 	data8 sys32_lseek
 	data8 sys_getpid	  /* 20 */
-	data8 sys_mount
+	data8 compat_sys_mount
 	data8 sys_oldumount
 	data8 sys_setuid	/* 16-bit version */
 	data8 sys_getuid	/* 16-bit version */
diff -Nru a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c
--- a/arch/ia64/ia32/ia32_support.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ia64/ia32/ia32_support.c	Sat Apr  3 19:38:41 2004
@@ -134,8 +134,6 @@
 	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 -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c	Sat Apr  3 19:38:44 2004
+++ b/arch/ia64/ia32/sys_ia32.c	Sat Apr  3 19:38:44 2004
@@ -34,9 +34,6 @@
 #include <linux/slab.h>
 #include <linux/uio.h>
 #include <linux/nfs_fs.h>
-#include <linux/smb_fs.h>
-#include <linux/smb_mount.h>
-#include <linux/ncp_fs.h>
 #include <linux/quota.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -1023,143 +1020,6 @@
 	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 +1033,6 @@
 #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 +1044,36 @@
 	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;
@@ -2968,157 +2380,6 @@
 } 
 
 #ifdef	NOTYET  /* UNTESTED FOR IA64 FROM HERE DOWN */
-
-struct ncp_mount_data32 {
-	int version;
-	unsigned int ncp_fd;
-	compat_uid_t mounted_uid;
-	int wdog_pid;
-	unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
-	unsigned int time_out;
-	unsigned int retry_count;
-	unsigned int flags;
-	compat_uid_t uid;
-	compat_gid_t gid;
-	compat_mode_t file_mode;
-	compat_mode_t dir_mode;
-};
-
-static void *
-do_ncp_super_data_conv(void *raw_data)
-{
-	struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
-	struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
-
-	n->dir_mode = n32->dir_mode;
-	n->file_mode = n32->file_mode;
-	n->gid = n32->gid;
-	n->uid = n32->uid;
-	memmove (n->mounted_vol, n32->mounted_vol,
-		 (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
-	n->wdog_pid = n32->wdog_pid;
-	n->mounted_uid = n32->mounted_uid;
-	return raw_data;
-}
-
-struct smb_mount_data32 {
-	int version;
-	compat_uid_t mounted_uid;
-	compat_uid_t uid;
-	compat_gid_t gid;
-	compat_mode_t file_mode;
-	compat_mode_t dir_mode;
-};
-
-static void *
-do_smb_super_data_conv(void *raw_data)
-{
-	struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
-	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
-
-	if (s32->version != SMB_MOUNT_OLDVERSION)
-		goto out;
-	s->version = s32->version;
-	s->mounted_uid = s32->mounted_uid;
-	s->uid = s32->uid;
-	s->gid = s32->gid;
-	s->file_mode = s32->file_mode;
-	s->dir_mode = s32->dir_mode;
-out:
-	return raw_data;
-}
-
-static int
-copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
-{
-	int i;
-	unsigned long page;
-	struct vm_area_struct *vma;
-
-	*kernel = 0;
-	if(!user)
-		return 0;
-	vma = find_vma(current->mm, (unsigned long)user);
-	if(!vma || (unsigned long)user < vma->vm_start)
-		return -EFAULT;
-	if(!(vma->vm_flags & VM_READ))
-		return -EFAULT;
-	i = vma->vm_end - (unsigned long) user;
-	if(PAGE_SIZE <= (unsigned long) i)
-		i = PAGE_SIZE - 1;
-	if(!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
-	if(copy_from_user((void *) page, user, i)) {
-		free_page(page);
-		return -EFAULT;
-	}
-	*kernel = page;
-	return 0;
-}
-
-#define SMBFS_NAME	"smbfs"
-#define NCPFS_NAME	"ncpfs"
-
-asmlinkage long
-sys32_mount(char *dev_name, char *dir_name, char *type,
-	    unsigned long new_flags, u32 data)
-{
-	unsigned long type_page;
-	int err, is_smb, is_ncp;
-
-	if(!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	is_smb = is_ncp = 0;
-	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
-	if(err)
-		return err;
-	if(type_page) {
-		is_smb = !strcmp((char *)type_page, SMBFS_NAME);
-		is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
-	}
-	if(!is_smb && !is_ncp) {
-		if(type_page)
-			free_page(type_page);
-		return sys_mount(dev_name, dir_name, type, new_flags,
-				 (void *)AA(data));
-	} else {
-		unsigned long dev_page, dir_page, data_page;
-
-		err = copy_mount_stuff_to_kernel((const void *)dev_name,
-						 &dev_page);
-		if(err)
-			goto out;
-		err = copy_mount_stuff_to_kernel((const void *)dir_name,
-						 &dir_page);
-		if(err)
-			goto dev_out;
-		err = copy_mount_stuff_to_kernel((const void *)AA(data),
-						 &data_page);
-		if(err)
-			goto dir_out;
-		if(is_ncp)
-			do_ncp_super_data_conv((void *)data_page);
-		else if(is_smb)
-			do_smb_super_data_conv((void *)data_page);
-		else
-			panic("The problem is here...");
-		err = do_mount((char *)dev_page, (char *)dir_page,
-				(char *)type_page, new_flags,
-				(void *)data_page);
-		if(data_page)
-			free_page(data_page);
-	dir_out:
-		if(dir_page)
-			free_page(dir_page);
-	dev_out:
-		if(dev_page)
-			free_page(dev_page);
-	out:
-		if(type_page)
-			free_page(type_page);
-		return err;
-	}
-}
 
 asmlinkage long sys32_setreuid(compat_uid_t ruid, compat_uid_t euid)
 {
diff -Nru a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
--- a/arch/ia64/kernel/Makefile	Sat Apr  3 19:38:56 2004
+++ b/arch/ia64/kernel/Makefile	Sat Apr  3 19:38:56 2004
@@ -6,13 +6,12 @@
 
 obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o	\
 	 irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o		\
-	 salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o unwind.o
+	 salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o unwind.o mca.o mca_asm.o
 
 obj-$(CONFIG_EFI_VARS)		+= efivars.o
 obj-$(CONFIG_IA64_BRL_EMU)	+= brl_emu.o
 obj-$(CONFIG_IA64_GENERIC)	+= acpi-ext.o
 obj-$(CONFIG_IA64_HP_ZX1)	+= acpi-ext.o
-obj-$(CONFIG_IA64_MCA)		+= mca.o mca_asm.o
 obj-$(CONFIG_IA64_PALINFO)	+= palinfo.o
 obj-$(CONFIG_IOSAPIC)		+= iosapic.o
 obj-$(CONFIG_MODULES)		+= module.o
diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
--- a/arch/ia64/kernel/acpi.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/kernel/acpi.c	Sat Apr  3 19:38:43 2004
@@ -62,8 +62,6 @@
 unsigned char acpi_kbd_controller_present = 1;
 unsigned char acpi_legacy_devices;
 
-int acpi_disabled;	/* XXX this shouldn't be needed---we can't boot without ACPI! */
-
 const char *
 acpi_get_sysname (void)
 {
@@ -626,6 +624,7 @@
 	return 0;
 }
 
+/* deprecated in favor of acpi_gsi_to_irq */
 int
 acpi_irq_to_vector (u32 gsi)
 {
@@ -633,6 +632,23 @@
 		return isa_irq_to_vector(gsi);
 
 	return gsi_to_vector(gsi);
+}
+
+int
+acpi_gsi_to_irq (u32 gsi, unsigned int *irq)
+{
+	int vector;
+
+	if (has_8259 && gsi < 16)
+		*irq = isa_irq_to_vector(gsi);
+	else {
+		vector = gsi_to_vector(gsi);
+		if (vector == -1)
+			return -1;
+
+		*irq = vector;
+	}
+	return 0;
 }
 
 int
diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
--- a/arch/ia64/kernel/efi.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ia64/kernel/efi.c	Sat Apr  3 19:38:41 2004
@@ -399,9 +399,7 @@
 	int pal_code_count = 0;
 	u64 mask, psr;
 	u64 vaddr;
-#ifdef CONFIG_IA64_MCA
 	int cpu;
-#endif
 
 	efi_map_start = __va(ia64_boot_param->efi_memmap);
 	efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
@@ -463,13 +461,11 @@
 		ia64_set_psr(psr);		/* restore psr */
 		ia64_srlz_i();
 
-#ifdef CONFIG_IA64_MCA
 		cpu = smp_processor_id();
 
 		/* insert this TR into our list for MCA recovery purposes */
 		ia64_mca_tlb_list[cpu].pal_base = vaddr & mask;
 		ia64_mca_tlb_list[cpu].pal_paddr = pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL));
-#endif
 	}
 }
 
diff -Nru a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
--- a/arch/ia64/kernel/gate.S	Sat Apr  3 19:38:55 2004
+++ b/arch/ia64/kernel/gate.S	Sat Apr  3 19:38:55 2004
@@ -234,7 +234,7 @@
 	br.call.sptk.many rp=b6			// call the signal handler
 .ret0:	adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
 	;;
-	ld8 r15=[base0],(CFM_OFF-BSP_OFF)	// fetch sc_ar_bsp and advance to CFM_OFF
+	ld8 r15=[base0]				// fetch sc_ar_bsp
 	mov r14=ar.bsp
 	;;
 	cmp.ne p1,p0=r14,r15			// do we need to restore the rbs?
diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
--- a/arch/ia64/kernel/head.S	Sat Apr  3 19:38:45 2004
+++ b/arch/ia64/kernel/head.S	Sat Apr  3 19:38:45 2004
@@ -816,7 +816,7 @@
 	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 @@
 	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 -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
--- a/arch/ia64/kernel/iosapic.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/kernel/iosapic.c	Sat Apr  3 19:38:43 2004
@@ -170,7 +170,7 @@
 }
 
 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 @@
 	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 @@
 	       (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 @@
 	       (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 @@
 	    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 @@
 	/* 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 -Nru a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
--- a/arch/ia64/kernel/irq_ia64.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/kernel/irq_ia64.c	Sat Apr  3 19:38:43 2004
@@ -57,6 +57,21 @@
 };
 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 -Nru a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c
--- a/arch/ia64/kernel/machvec.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/kernel/machvec.c	Sat Apr  3 19:38:43 2004
@@ -50,8 +50,27 @@
 EXPORT_SYMBOL(machvec_noop);
 
 void
-machvec_memory_fence (void)
+machvec_setup (char **arg)
+{
+}
+EXPORT_SYMBOL(machvec_setup);
+
+void
+machvec_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+EXPORT_SYMBOL(machvec_timer_interrupt);
+
+void
+machvec_dma_sync_single (struct device *hwdev, dma_addr_t dma_handle, size_t size, int dir)
+{
+	mb();
+}
+EXPORT_SYMBOL(machvec_dma_sync_single);
+
+void
+machvec_dma_sync_sg (struct device *hwdev, struct scatterlist *sg, int n, int dir)
 {
 	mb();
 }
-EXPORT_SYMBOL(machvec_memory_fence);
+EXPORT_SYMBOL(machvec_dma_sync_sg);
diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
--- a/arch/ia64/kernel/mca.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/kernel/mca.c	Sat Apr  3 19:38:43 2004
@@ -103,8 +103,6 @@
 
 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 @@
 				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 -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/kernel/process.c	Sat Apr  3 19:38:43 2004
@@ -159,16 +159,25 @@
 		ia64_do_signal(oldset, scr, in_syscall);
 }
 
+static int pal_halt = 1;
+static int __init nohalt_setup(char * str)
+{
+	pal_halt = 0;
+	return 1;
+}
+__setup("nohalt", nohalt_setup);
+
 /*
  * We use this if we don't have any better idle routine..
  */
 void
 default_idle (void)
 {
-#ifdef CONFIG_IA64_PAL_IDLE
-	if (!need_resched())
-		safe_halt();
-#endif
+	unsigned long pmu_active = ia64_getreg(_IA64_REG_PSR) & (IA64_PSR_PP | IA64_PSR_UP);
+
+	while (!need_resched())
+		if (pal_halt && !pmu_active)
+			safe_halt();
 }
 
 void __attribute__((noreturn))
@@ -574,8 +583,8 @@
 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 -Nru a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c
--- a/arch/ia64/kernel/sal.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ia64/kernel/sal.c	Sat Apr  3 19:38:56 2004
@@ -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 = (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 @@
 	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 -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
--- a/arch/ia64/kernel/setup.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ia64/kernel/setup.c	Sat Apr  3 19:38:41 2004
@@ -229,6 +229,38 @@
 #endif
 }
 
+static void __init
+io_port_init (void)
+{
+	extern unsigned long ia64_iobase;
+	unsigned long phys_iobase;
+
+	/*
+	 *  Set `iobase' to the appropriate address in region 6 (uncached access range).
+	 *
+	 *  The EFI memory map is the "preferred" location to get the I/O port space base,
+	 *  rather the relying on AR.KR0. This should become more clear in future SAL
+	 *  specs. We'll fall back to getting it out of AR.KR0 if no appropriate entry is
+	 *  found in the memory map.
+	 */
+	phys_iobase = efi_get_iobase();
+	if (phys_iobase)
+		/* set AR.KR0 since this is all we use it for anyway */
+		ia64_set_kr(IA64_KR_IO_BASE, phys_iobase);
+	else {
+		phys_iobase = ia64_get_kr(IA64_KR_IO_BASE);
+		printk(KERN_INFO "No I/O port range found in EFI memory map, falling back "
+		       "to AR.KR0\n");
+		printk(KERN_INFO "I/O port base = 0x%lx\n", phys_iobase);
+	}
+	ia64_iobase = (unsigned long) ioremap(phys_iobase, 0);
+
+	/* setup legacy IO port space */
+	io_space[0].mmio_base = ia64_iobase;
+	io_space[0].sparse = 1;
+	num_io_spaces = 1;
+}
+
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 static void __init
 setup_serial_legacy (void)
@@ -251,9 +283,6 @@
 void __init
 setup_arch (char **cmdline_p)
 {
-	extern unsigned long ia64_iobase;
-	unsigned long phys_iobase;
-
 	unw_init();
 
 	ia64_patch_vtop((u64) __start___vtop_patchlist, (u64) __end___vtop_patchlist);
@@ -262,6 +291,11 @@
 	strlcpy(saved_command_line, *cmdline_p, sizeof(saved_command_line));
 
 	efi_init();
+	io_port_init();
+
+#ifdef CONFIG_IA64_GENERIC
+	machvec_init(acpi_get_sysname());
+#endif
 
 #ifdef CONFIG_ACPI_BOOT
 	/* Initialize the ACPI boot-time table parser */
@@ -280,35 +314,6 @@
 	/* process SAL system table: */
 	ia64_sal_init(efi.sal_systab);
 
-#ifdef CONFIG_IA64_GENERIC
-	machvec_init(acpi_get_sysname());
-#endif
-
-	/*
-	 *  Set `iobase' to the appropriate address in region 6 (uncached access range).
-	 *
-	 *  The EFI memory map is the "preferred" location to get the I/O port space base,
-	 *  rather the relying on AR.KR0. This should become more clear in future SAL
-	 *  specs. We'll fall back to getting it out of AR.KR0 if no appropriate entry is
-	 *  found in the memory map.
-	 */
-	phys_iobase = efi_get_iobase();
-	if (phys_iobase)
-		/* set AR.KR0 since this is all we use it for anyway */
-		ia64_set_kr(IA64_KR_IO_BASE, phys_iobase);
-	else {
-		phys_iobase = ia64_get_kr(IA64_KR_IO_BASE);
-		printk(KERN_INFO "No I/O port range found in EFI memory map, falling back "
-		       "to AR.KR0\n");
-		printk(KERN_INFO "I/O port base = 0x%lx\n", phys_iobase);
-	}
-	ia64_iobase = (unsigned long) ioremap(phys_iobase, 0);
-
-	/* setup legacy IO port space */
-	io_space[0].mmio_base = ia64_iobase;
-	io_space[0].sparse = 1;
-	num_io_spaces = 1;
-
 #ifdef CONFIG_SMP
 	cpu_physical_id(0) = hard_smp_processor_id();
 #endif
@@ -355,10 +360,8 @@
 # endif
 #endif
 
-#ifdef CONFIG_IA64_MCA
 	/* enable IA-64 Machine Check Abort Handling */
 	ia64_mca_init();
-#endif
 
 	platform_setup(cmdline_p);
 	paging_init();
diff -Nru a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
--- a/arch/ia64/kernel/smp.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ia64/kernel/smp.c	Sat Apr  3 19:38:56 2004
@@ -91,9 +91,6 @@
 	unsigned long *pending_ipis = &__ia64_per_cpu_var(ipi_operation);
 	unsigned long ops;
 
-	/* Count this now; we may make a call that never returns. */
-	local_cpu_data->ipi_count++;
-
 	mb();	/* Order interrupt and bit testing. */
 	while ((ops = xchg(pending_ipis, 0)) != 0) {
 		mb();	/* Order bit clearing and data access. */
@@ -337,17 +334,6 @@
 	return 0;
 }
 EXPORT_SYMBOL(smp_call_function);
-
-void
-smp_do_timer (struct pt_regs *regs)
-{
-	int user = user_mode(regs);
-
-	if (--local_cpu_data->prof_counter <= 0) {
-		local_cpu_data->prof_counter = local_cpu_data->prof_multiplier;
-		update_process_times(user);
-	}
-}
 
 /*
  * this function calls the 'stop' function on all other CPUs in the system.
diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
--- a/arch/ia64/kernel/smpboot.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ia64/kernel/smpboot.c	Sat Apr  3 19:38:42 2004
@@ -265,8 +265,6 @@
 static inline void __init
 smp_setup_percpu_timer (void)
 {
-	local_cpu_data->prof_counter = 1;
-	local_cpu_data->prof_multiplier = 1;
 }
 
 static void __init
@@ -300,9 +298,7 @@
 	 */
 	ia64_set_kr(IA64_KR_IO_BASE, __pa(ia64_iobase));
 
-#ifdef CONFIG_IA64_MCA
 	ia64_mca_cmc_vector_setup();	/* Setup vector on AP & enable */
-#endif
 
 #ifdef CONFIG_PERFMON
 	pfm_init_percpu();
diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
--- a/arch/ia64/kernel/time.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ia64/kernel/time.c	Sat Apr  3 19:38:42 2004
@@ -255,9 +255,13 @@
 	ia64_do_profile(regs);
 
 	while (1) {
-
 #ifdef CONFIG_SMP
-		smp_do_timer(regs);
+		/*
+		 * For UP, this is done in do_timer().  Weird, but
+		 * fixing that would require updates to all
+		 * platforms.
+		 */
+		update_process_times(user_mode(regs));
 #endif
 		new_itm += local_cpu_data->itm_delta;
 
@@ -280,17 +284,19 @@
 	}
 
 	do {
-	    /*
-	     * If we're too close to the next clock tick for comfort, we increase the
-	     * safety margin by intentionally dropping the next tick(s).  We do NOT update
-	     * itm.next because that would force us to call do_timer() which in turn would
-	     * let our clock run too fast (with the potentially devastating effect of
-	     * losing monotony of time).
-	     */
-	    while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2))
-	      new_itm += local_cpu_data->itm_delta;
-	    ia64_set_itm(new_itm);
-	    /* double check, in case we got hit by a (slow) PMI: */
+		/*
+		 * If we're too close to the next clock tick for
+		 * comfort, we increase the safety margin by
+		 * intentionally dropping the next tick(s).  We do NOT
+		 * update itm.next because that would force us to call
+		 * do_timer() which in turn would let our clock run
+		 * too fast (with the potentially devastating effect
+		 * of losing monotony of time).
+		 */
+		while (!time_after(new_itm, ia64_get_itc() + local_cpu_data->itm_delta/2))
+			new_itm += local_cpu_data->itm_delta;
+		ia64_set_itm(new_itm);
+		/* double check, in case we got hit by a (slow) PMI: */
 	} while (time_after_eq(ia64_get_itc(), new_itm));
 	return IRQ_HANDLED;
 }
diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
--- a/arch/ia64/kernel/traps.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ia64/kernel/traps.c	Sat Apr  3 19:38:56 2004
@@ -488,7 +488,7 @@
 			siginfo.si_isr = isr;
 			force_sig_info(sig, &siginfo, current);
 			return;
-		} else if (done_with_exception(regs))
+		} else if (ia64_done_with_exception(regs))
 			return;
 		sprintf(buf, "NaT consumption");
 		break;
diff -Nru a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
--- a/arch/ia64/kernel/unaligned.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ia64/kernel/unaligned.c	Sat Apr  3 19:38:55 2004
@@ -1486,7 +1486,7 @@
 	/* something went wrong... */
 	if (!user_mode(regs)) {
 		if (eh) {
-			handle_exception(regs, eh);
+			ia64_handle_exception(regs, eh);
 			goto done;
 		}
 		die_if_kernel("error during unaligned kernel access\n", regs, ret);
diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
--- a/arch/ia64/kernel/unwind.c	Sat Apr  3 19:38:57 2004
+++ b/arch/ia64/kernel/unwind.c	Sat Apr  3 19:38:57 2004
@@ -1746,7 +1746,7 @@
 			if (!state->pri_unat_loc)
 				state->pri_unat_loc = &state->sw->ar_unat;
 			/* register off. is a multiple of 8, so the least 3 bits (type) are 0 */
-			s[dst+1] = (*state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;
+			s[dst+1] = ((unsigned long) state->pri_unat_loc - s[dst]) | UNW_NAT_MEMSTK;
 			break;
 
 		      case UNW_INSN_SETNAT_TYPE:
diff -Nru a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
--- a/arch/ia64/kernel/vmlinux.lds.S	Sat Apr  3 19:38:55 2004
+++ b/arch/ia64/kernel/vmlinux.lds.S	Sat Apr  3 19:38:55 2004
@@ -12,6 +12,11 @@
 OUTPUT_ARCH(ia64)
 ENTRY(phys_start)
 jiffies = jiffies_64;
+PHDRS {
+  code   PT_LOAD;
+  percpu PT_LOAD;
+  data   PT_LOAD;
+}
 SECTIONS
 {
   /* Sections to be discarded */
@@ -26,6 +31,7 @@
   v = PAGE_OFFSET;	/* this symbol is here to make debugging easier... */
   phys_start = _start - LOAD_OFFSET;
 
+  code : { } :code
   . = KERNEL_START;
 
   _text = .;
@@ -173,6 +179,7 @@
         { *(.data.cacheline_aligned) }
 
   /* Per-cpu data: */
+  percpu : { } :percpu
   . = ALIGN(PERCPU_PAGE_SIZE);
   __phys_per_cpu_start = .;
   .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET)
@@ -183,6 +190,7 @@
 	}
   . = __phys_per_cpu_start + PERCPU_PAGE_SIZE;	/* ensure percpu data fits into percpu page size */
 
+  data : { } :data
   .data : AT(ADDR(.data) - LOAD_OFFSET)
 	{ *(.data) *(.data1) *(.gnu.linkonce.d*) CONSTRUCTORS }
 
@@ -205,6 +213,7 @@
 
   _end = .;
 
+  code : { } :code
   /* Stabs debugging sections.  */
   .stab 0 : { *(.stab) }
   .stabstr 0 : { *(.stabstr) }
diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
--- a/arch/ia64/lib/swiotlb.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ia64/lib/swiotlb.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
  *
  * 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 @@
  * 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;
 
@@ -472,6 +498,12 @@
 			sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir);
 }
 
+int
+swiotlb_dma_mapping_error (dma_addr_t dma_addr)
+{
+	return 0;
+}
+
 /*
  * Return whether the given PCI device DMA address mask can be supported properly.  For
  * example, if your device can only drive the low 24-bits during PCI bus mastering, then
@@ -488,8 +520,11 @@
 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_dma_mapping_error);
 EXPORT_SYMBOL(swiotlb_alloc_coherent);
 EXPORT_SYMBOL(swiotlb_free_coherent);
 EXPORT_SYMBOL(swiotlb_dma_supported);
diff -Nru a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
--- a/arch/ia64/mm/contig.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ia64/mm/contig.c	Sat Apr  3 19:38:42 2004
@@ -46,6 +46,8 @@
 	printk("Free swap:       %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
 	i = max_mapnr;
 	while (i-- > 0) {
+		if (!pfn_valid(i))
+			continue;
 		total++;
 		if (PageReserved(mem_map+i))
 			reserved++;
diff -Nru a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
--- a/arch/ia64/mm/discontig.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ia64/mm/discontig.c	Sat Apr  3 19:38:55 2004
@@ -499,6 +499,8 @@
 	for_each_pgdat(pgdat) {
 		printk("Node ID: %d\n", pgdat->node_id);
 		for(i = 0; i < pgdat->node_spanned_pages; i++) {
+			if (!ia64_pfn_valid(pgdat->node_start_pfn+i))
+				continue;
 			if (PageReserved(pgdat->node_mem_map+i))
 				reserved++;
 			else if (PageSwapCache(pgdat->node_mem_map+i))
diff -Nru a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c
--- a/arch/ia64/mm/extable.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ia64/mm/extable.c	Sat Apr  3 19:38:42 2004
@@ -81,7 +81,7 @@
 }
 
 void
-handle_exception (struct pt_regs *regs, const struct exception_table_entry *e)
+ia64_handle_exception (struct pt_regs *regs, const struct exception_table_entry *e)
 {
 	long fix = (u64) &e->cont + e->cont;
 
diff -Nru a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
--- a/arch/ia64/mm/fault.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ia64/mm/fault.c	Sat Apr  3 19:38:56 2004
@@ -213,7 +213,7 @@
 		return;
 	}
 
-	if (done_with_exception(regs))
+	if (ia64_done_with_exception(regs))
 		return;
 
 	/*
@@ -233,7 +233,7 @@
 	bust_spinlocks(1);
 
 	if (address < PAGE_SIZE)
-		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference (address %016lx)\n", address);
 	else
 		printk(KERN_ALERT "Unable to handle kernel paging request at "
 		       "virtual address %016lx\n", address);
diff -Nru a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
--- a/arch/ia64/mm/hugetlbpage.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/mm/hugetlbpage.c	Sat Apr  3 19:38:43 2004
@@ -592,6 +592,13 @@
 	return 1;
 }
 
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+	return htlbzone_pages * (HPAGE_SIZE / PAGE_SIZE);
+}
+EXPORT_SYMBOL(hugetlb_total_pages);
+
 static struct page *hugetlb_nopage(struct vm_area_struct * area, unsigned long address, int *unused)
 {
 	BUG();
diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
--- a/arch/ia64/mm/init.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/mm/init.c	Sat Apr  3 19:38:43 2004
@@ -279,9 +279,7 @@
 {
 	unsigned long psr, pta, impl_va_bits;
 	extern void __init tlb_init (void);
-#ifdef CONFIG_IA64_MCA
 	int cpu;
-#endif
 
 #ifdef CONFIG_DISABLE_VHPT
 #	define VHPT_ENABLE_BIT	0
@@ -346,7 +344,6 @@
 	ia64_set_rr(HPAGE_REGION_BASE, HPAGE_SHIFT << 2);
 #endif
 
-#ifdef	CONFIG_IA64_MCA
 	cpu = smp_processor_id();
 
 	/* mca handler uses cr.lid as key to pick the right entry */
@@ -360,7 +357,6 @@
 	ia64_mca_tlb_list[cpu].ptce_count[1] = local_cpu_data->ptce_count[1];
 	ia64_mca_tlb_list[cpu].ptce_stride[0] = local_cpu_data->ptce_stride[0];
 	ia64_mca_tlb_list[cpu].ptce_stride[1] = local_cpu_data->ptce_stride[1];
-#endif
 }
 
 #ifdef CONFIG_VIRTUAL_MEM_MAP
@@ -459,8 +455,11 @@
 ia64_pfn_valid (unsigned long pfn)
 {
 	char byte;
+	struct page *pg = pfn_to_page(pfn);
 
-	return __get_user(byte, (char *) pfn_to_page(pfn)) == 0;
+	return     (__get_user(byte, (char *) pg) == 0)
+		&& ((((u64)pg & PAGE_MASK) == (((u64)(pg + 1) - 1) & PAGE_MASK))
+			|| (__get_user(byte, (char *) (pg + 1) - 1) == 0));
 }
 EXPORT_SYMBOL(ia64_pfn_valid);
 
diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
--- a/arch/ia64/pci/pci.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/pci/pci.c	Sat Apr  3 19:38:43 2004
@@ -57,17 +57,16 @@
 	((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,63 @@
 	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_revision >= SAL_VERSION_CODE(3, 2)) {
+		printk("Using SAL 3.2 to access PCI config space\n");
+		raw_pci_ops = &pci_sal_ext_ops;
+	}
+	return 0;
+}
+
+arch_initcall(pci_set_sal_ops);
 
 
 static int
@@ -139,7 +186,8 @@
 }
 
 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;
 
@@ -320,6 +368,7 @@
 				dev->resource[i].end   += window->offset;
 			}
 		}
+		pci_claim_resource(dev, i);
 	}
 }
 
diff -Nru a/arch/ia64/sn/fakeprom/fw-emu.c b/arch/ia64/sn/fakeprom/fw-emu.c
--- a/arch/ia64/sn/fakeprom/fw-emu.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ia64/sn/fakeprom/fw-emu.c	Sat Apr  3 19:38:54 2004
@@ -397,7 +397,7 @@
         fix_virt_function_pointer((void**)&runtime->set_variable);
         fix_virt_function_pointer((void**)&runtime->get_next_high_mono_count);
         fix_virt_function_pointer((void**)&runtime->reset_system);
-        return EFI_SUCCESS;;
+        return EFI_SUCCESS;
 }
 
 void
diff -Nru a/arch/ia64/sn/io/hwgfs/ramfs.c b/arch/ia64/sn/io/hwgfs/ramfs.c
--- a/arch/ia64/sn/io/hwgfs/ramfs.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ia64/sn/io/hwgfs/ramfs.c	Sat Apr  3 19:38:54 2004
@@ -84,7 +84,7 @@
 	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 -Nru a/arch/ia64/sn/io/machvec/pci_dma.c b/arch/ia64/sn/io/machvec/pci_dma.c
--- a/arch/ia64/sn/io/machvec/pci_dma.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ia64/sn/io/machvec/pci_dma.c	Sat Apr  3 19:38:42 2004
@@ -152,7 +152,7 @@
 	 *   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 @@
 		}
 	}
 
-	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_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 @@
  * 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 @@
  * 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,58 @@
 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_for_device);
+
+int
+sn_dma_mapping_error(dma_addr_t dma_addr)
+{
+	return 0;
 }
-EXPORT_SYMBOL(sn_dma_sync_sg);
 
+EXPORT_SYMBOL(sn_dma_mapping_error);
 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 -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c
--- a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	Sat Apr  3 19:38:57 2004
+++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c	Sat Apr  3 19:38:57 2004
@@ -2501,7 +2501,7 @@
     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 @@
 		memset(buffer, 0, 1024);
 		vsnprintf(buffer, 1024, format, ap);
 		va_end(ap);
-		printk("", "%s", buffer);
+		printk("%s", buffer);
 		kfree(buffer);
 	    }
         }
diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c
--- a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c	Sat Apr  3 19:38:54 2004
@@ -101,7 +101,7 @@
 {
 	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 -Nru a/arch/ia64/sn/io/sn2/pciio.c b/arch/ia64/sn/io/sn2/pciio.c
--- a/arch/ia64/sn/io/sn2/pciio.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ia64/sn/io/sn2/pciio.c	Sat Apr  3 19:38:56 2004
@@ -822,7 +822,7 @@
 			     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 @@
 
     hwgraph_vertex_unref(pconn);
     hwgraph_vertex_destroy(pconn);
-    
 }
 
 /*ARGSUSED */
@@ -927,7 +926,7 @@
 		win_alloc->wa_pages = size;
 	}
 
-	return new_res->start;;
+	return new_res->start;
 }
 
 /*
diff -Nru a/arch/ia64/sn/io/sn2/pic.c b/arch/ia64/sn/io/sn2/pic.c
--- a/arch/ia64/sn/io/sn2/pic.c	Sat Apr  3 19:38:44 2004
+++ b/arch/ia64/sn/io/sn2/pic.c	Sat Apr  3 19:38:44 2004
@@ -685,7 +685,7 @@
 
     /* Block off the range used by PROM. */
     res->start = prom_base_addr;
-    res->end = prom_base_addr + (prom_base_size - 1);;
+    res->end = prom_base_addr + (prom_base_size - 1);
     status = request_resource(&pcibr_soft->bs_mem_win_root_resource, res);
     if (status)
 	panic("PCIBR:Unable to request_resource()\n");
diff -Nru a/arch/ia64/sn/io/sn2/shub.c b/arch/ia64/sn/io/sn2/shub.c
--- a/arch/ia64/sn/io/sn2/shub.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/sn/io/sn2/shub.c	Sat Apr  3 19:38:43 2004
@@ -160,11 +160,13 @@
 shubstats_ioctl(struct inode *inode, struct file *file,
         unsigned int cmd, unsigned long arg)
 {
-        cnodeid_t       cnode;
-        uint64_t        longarg;
+	cnodeid_t       cnode;
+	uint64_t        longarg;
+	uint64_t        intarg;
+	uint64_t        regval[2];
 	int		nasid;
 
-        cnode = (cnodeid_t)file->f_dentry->d_fsdata;
+        cnode = (cnodeid_t)(u64)file->f_dentry->d_fsdata;
         if (cnode < 0 || cnode >= numnodes)
                 return -ENODEV;
 
@@ -200,6 +202,38 @@
 		}
 		break;
 
+	case SNDRV_SHUB_GETMMR32:
+		intarg = shub_mmr_read32(cnode, arg);
+		if (copy_to_user((void *)arg, &intarg,
+					sizeof(intarg))) {
+		    return -EFAULT;
+		}
+		break;
+ 
+	case SNDRV_SHUB_GETMMR64:
+	case SNDRV_SHUB_GETMMR64_IO:
+		if (cmd == SNDRV_SHUB_GETMMR64)
+		    longarg = shub_mmr_read(cnode, arg);
+		else
+		    longarg = shub_mmr_read_iospace(cnode, arg);
+		if (copy_to_user((void *)arg, &longarg, sizeof(longarg)))
+		    return -EFAULT;
+		break;
+ 
+	case SNDRV_SHUB_PUTMMR64:
+	case SNDRV_SHUB_PUTMMR64_IO:
+		if (copy_from_user((void *)regval, (void *)arg, sizeof(regval)))
+		    return -EFAULT;
+		if (regval[0] & 0x7) {
+		    printk("Error: configure_shub_stats: unaligned address 0x%016lx\n", regval[0]);
+		    return -EINVAL;
+		}
+		if (cmd == SNDRV_SHUB_PUTMMR64)
+		    shub_mmr_write(cnode, (shubreg_t)regval[0], regval[1]);
+		else
+		    shub_mmr_write_iospace(cnode, (shubreg_t)regval[0], regval[1]);
+		break;
+ 
 	default:
 		return -EINVAL;
 	}
@@ -210,255 +244,3 @@
 struct file_operations shub_mon_fops = {
 	        .ioctl          = shubstats_ioctl,
 };
-
-/*
- * "linkstatd" kernel thread to export SGI Numalink
- * stats via /proc/sgi_sn/linkstats
- */
-static struct s_linkstats {
-	uint64_t	hs_ni_sn_errors[2];
-	uint64_t	hs_ni_cb_errors[2];
-	uint64_t	hs_ni_retry_errors[2];
-	int		hs_ii_up;
-	uint64_t	hs_ii_sn_errors;
-	uint64_t	hs_ii_cb_errors;
-	uint64_t	hs_ii_retry_errors;
-} *sn_linkstats;
-
-static spinlock_t    sn_linkstats_lock;
-static unsigned long sn_linkstats_starttime;
-static unsigned long sn_linkstats_samples;
-static unsigned long sn_linkstats_overflows;
-static unsigned long sn_linkstats_update_msecs;
-
-void
-sn_linkstats_reset(unsigned long msecs)
-{
-	int		    cnode;
-	uint64_t	    iio_wstat;
-	uint64_t	    llp_csr_reg;
-
-	spin_lock(&sn_linkstats_lock);
-	memset(sn_linkstats, 0, numnodes * sizeof(struct s_linkstats));
-	for (cnode=0; cnode < numnodes; cnode++) {
-	    shub_mmr_write(cnode, SH_NI0_LLP_ERR, 0L);
-	    shub_mmr_write(cnode, SH_NI1_LLP_ERR, 0L);
-	    shub_mmr_write_iospace(cnode, IIO_LLP_LOG, 0L);
-
-	    /* zero the II retry counter */
-	    iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT);
-	    iio_wstat &= 0xffffffffff00ffff; /* bits 23:16 */
-	    shub_mmr_write_iospace(cnode, IIO_WSTAT, iio_wstat);
-
-	    /* Check if the II xtalk link is working */
-	    llp_csr_reg = shub_mmr_read_iospace(cnode, IIO_LLP_CSR);
-	    if (llp_csr_reg & IIO_LLP_CSR_IS_UP)
-		sn_linkstats[cnode].hs_ii_up = 1;
-	}
-
-    	sn_linkstats_update_msecs = msecs;
-	sn_linkstats_samples = 0;
-	sn_linkstats_overflows = 0;
-	sn_linkstats_starttime = jiffies;
-	spin_unlock(&sn_linkstats_lock);
-}
-
-int
-linkstatd_thread(void *unused)
-{
-	int		    cnode;
-	int		    overflows;
-	uint64_t	    reg[2];
-	uint64_t	    iio_wstat = 0L;
-	ii_illr_u_t	    illr;
-	struct s_linkstats  *lsp;
-	struct task_struct  *tsk = current;
-
-	daemonize("linkstatd");
-	set_user_nice(tsk, 19);
-	sigfillset(&tsk->blocked);
-	strcpy(tsk->comm, "linkstatd");
-
-	while(1) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(sn_linkstats_update_msecs * HZ / 1000);
-
-		spin_lock(&sn_linkstats_lock);
-
-		overflows = 0;
-		for (lsp=sn_linkstats, cnode=0; cnode < numnodes; cnode++, lsp++) {
-			reg[0] = shub_mmr_read(cnode, SH_NI0_LLP_ERR);
-			reg[1] = shub_mmr_read(cnode, SH_NI1_LLP_ERR);
-			if (lsp->hs_ii_up) {
-			    illr = (ii_illr_u_t)shub_mmr_read_iospace(cnode, IIO_LLP_LOG);
-			    iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT);
-			}
-
-			if (!overflows && (
-			    (reg[0] & SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK) == 
-				     SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK ||
-			    (reg[0] & SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK) ==
-			             SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK ||
-			    (reg[1] & SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK) ==
-			             SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK ||
-			    (reg[1] & SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK) ==
-			             SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK ||
-			    (lsp->hs_ii_up && illr.ii_illr_fld_s.i_sn_cnt == IIO_LLP_SN_MAX) ||
-			    (lsp->hs_ii_up && illr.ii_illr_fld_s.i_cb_cnt == IIO_LLP_CB_MAX))) {
-			    overflows = 1;
-			}
-
-#define LINKSTAT_UPDATE(reg, cnt, mask, shift) cnt += (reg & mask) >> shift
-
-			LINKSTAT_UPDATE(reg[0], lsp->hs_ni_sn_errors[0],
-					SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_MASK,
-					SH_NI0_LLP_ERR_RX_SN_ERR_COUNT_SHFT);
-
-			LINKSTAT_UPDATE(reg[1], lsp->hs_ni_sn_errors[1],
-					SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_MASK,
-					SH_NI1_LLP_ERR_RX_SN_ERR_COUNT_SHFT);
-
-			LINKSTAT_UPDATE(reg[0], lsp->hs_ni_cb_errors[0],
-					SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_MASK,
-					SH_NI0_LLP_ERR_RX_CB_ERR_COUNT_SHFT);
-
-			LINKSTAT_UPDATE(reg[1], lsp->hs_ni_cb_errors[1],
-					SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_MASK,
-					SH_NI1_LLP_ERR_RX_CB_ERR_COUNT_SHFT);
-
-			LINKSTAT_UPDATE(reg[0], lsp->hs_ni_retry_errors[0],
-					SH_NI0_LLP_ERR_RETRY_COUNT_MASK,
-					SH_NI0_LLP_ERR_RETRY_COUNT_SHFT);
-
-			LINKSTAT_UPDATE(reg[1], lsp->hs_ni_retry_errors[1],
-					SH_NI1_LLP_ERR_RETRY_COUNT_MASK,
-					SH_NI1_LLP_ERR_RETRY_COUNT_SHFT);
-
-			if (lsp->hs_ii_up) {
-			    /* II sn and cb errors */
-			    lsp->hs_ii_sn_errors += illr.ii_illr_fld_s.i_sn_cnt;
-			    lsp->hs_ii_cb_errors += illr.ii_illr_fld_s.i_cb_cnt;
-			    lsp->hs_ii_retry_errors += (iio_wstat & 0x0000000000ff0000) >> 16;
-
-			    shub_mmr_write(cnode, SH_NI0_LLP_ERR, 0L);
-			    shub_mmr_write(cnode, SH_NI1_LLP_ERR, 0L);
-			    shub_mmr_write_iospace(cnode, IIO_LLP_LOG, 0L);
-
-			    /* zero the II retry counter */
-			    iio_wstat = shub_mmr_read_iospace(cnode, IIO_WSTAT);
-			    iio_wstat &= 0xffffffffff00ffff; /* bits 23:16 */
-			    shub_mmr_write_iospace(cnode, IIO_WSTAT, iio_wstat);
-			}
-		}
-
-		sn_linkstats_samples++;
-		if (overflows)
-		    sn_linkstats_overflows++;
-
-		spin_unlock(&sn_linkstats_lock);
-	}
-}
-
-static char *
-rate_per_minute(uint64_t val, uint64_t secs)
-{
-	static char	buf[16];
-	uint64_t	a=0, b=0, c=0, d=0;
-
-	if (secs) {
-		a = 60 * val / secs;
-		b = 60 * 10 * val / secs - (10 * a);
-		c = 60 * 100 * val / secs - (100 * a) - (10 * b);
-		d = 60 * 1000 * val / secs - (1000 * a) - (100 * b) - (10 * c);
-	}
-	sprintf(buf, "%4lu.%lu%lu%lu", a, b, c, d);
-
-	return buf;
-}
-
-int
-sn_linkstats_get(char *page)
-{
-	int			n = 0;
-	int			cnode;
-	int			nlport;
-	struct s_linkstats	*lsp;
-	nodepda_t		*npda;
-	uint64_t	    	snsum = 0;
-	uint64_t	    	cbsum = 0;
-	uint64_t	    	retrysum = 0;
-	uint64_t	    	snsum_ii = 0;
-	uint64_t	    	cbsum_ii = 0;
-	uint64_t	    	retrysum_ii = 0;
-	uint64_t		secs;
-
-	spin_lock(&sn_linkstats_lock);
-	secs = (jiffies - sn_linkstats_starttime) / HZ;
-
-	n += sprintf(page, "# SGI Numalink stats v1 : %lu samples, %lu o/flows, update %lu msecs\n",
-		sn_linkstats_samples, sn_linkstats_overflows, sn_linkstats_update_msecs);
-
-	n += sprintf(page+n, "%-37s %8s %8s %8s %8s\n",
-		"# Numalink", "sn errs", "cb errs", "cb/min", "retries");
-
-	for (lsp=sn_linkstats, cnode=0; cnode < numnodes; cnode++, lsp++) {
-		npda = NODEPDA(cnode);
-
-		/* two NL links on each SHub */
-		for (nlport=0; nlport < 2; nlport++) {
-			cbsum += lsp->hs_ni_cb_errors[nlport];
-			snsum += lsp->hs_ni_sn_errors[nlport];
-			retrysum += lsp->hs_ni_retry_errors[nlport];
-
-			/* avoid buffer overrun (should be using seq_read API) */
-			if (numnodes > 64)
-				continue;
-
-			n += sprintf(page + n, "/%s/link/%d  %8lu %8lu %8s %8lu\n",
-			    npda->hwg_node_name, nlport+1, lsp->hs_ni_sn_errors[nlport],
-			    lsp->hs_ni_cb_errors[nlport], 
-			    rate_per_minute(lsp->hs_ni_cb_errors[nlport], secs),
-			    lsp->hs_ni_retry_errors[nlport]);
-		}
-
-		/* one II port on each SHub (may not be connected) */
-		if (lsp->hs_ii_up) {
-		    n += sprintf(page + n, "/%s/xtalk   %8lu %8lu %8s %8lu\n",
-			npda->hwg_node_name, lsp->hs_ii_sn_errors,
-			lsp->hs_ii_cb_errors, rate_per_minute(lsp->hs_ii_cb_errors, secs),
-			lsp->hs_ii_retry_errors);
-
-		    snsum_ii += lsp->hs_ii_sn_errors;
-		    cbsum_ii += lsp->hs_ii_cb_errors;
-		    retrysum_ii += lsp->hs_ii_retry_errors;
-		}
-	}
-
-	n += sprintf(page + n, "%-37s %8lu %8lu %8s %8lu\n",
-		"System wide NL totals", snsum, cbsum, 
-		rate_per_minute(cbsum, secs), retrysum);
-
-	n += sprintf(page + n, "%-37s %8lu %8lu %8s %8lu\n",
-		"System wide II totals", snsum_ii, cbsum_ii, 
-		rate_per_minute(cbsum_ii, secs), retrysum_ii);
-
-	spin_unlock(&sn_linkstats_lock);
-
-	return n;
-}
-
-static int __init
-linkstatd_init(void)
-{
-	if (!ia64_platform_is("sn2"))
-		return -ENODEV;
-
-	spin_lock_init(&sn_linkstats_lock);
-	sn_linkstats = kmalloc(numnodes * sizeof(struct s_linkstats), GFP_KERNEL);
-	sn_linkstats_reset(60000UL); /* default 60 second update interval */
-	kernel_thread(linkstatd_thread, NULL, CLONE_KERNEL);
-
-	return 0;                                                                       
-}
-
-__initcall(linkstatd_init);
diff -Nru a/arch/ia64/sn/io/sn2/shub_intr.c b/arch/ia64/sn/io/sn2/shub_intr.c
--- a/arch/ia64/sn/io/sn2/shub_intr.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ia64/sn/io/sn2/shub_intr.c	Sat Apr  3 19:38:43 2004
@@ -200,7 +200,6 @@
 	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 @@
 	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 -Nru a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
--- a/arch/ia64/sn/kernel/irq.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ia64/sn/kernel/irq.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 }
 
 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 @@
 	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 -Nru a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c
--- a/arch/ia64/sn/kernel/mca.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ia64/sn/kernel/mca.c	Sat Apr  3 19:38:41 2004
@@ -1,17 +1,15 @@
 /*
- * File:	mca.c
- * Purpose:	SN specific MCA code.
- *
  * 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.
  *
- * Copyright (C) 2001-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  */
 
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
+#include <linux/vmalloc.h>
 #include <asm/sn/sgi.h>
 #include <asm/mca.h>
 #include <asm/sal.h>
@@ -30,41 +28,43 @@
 struct timer_list sn_cpei_timer;
 void sn_init_cpei_timer(void);
 
+/* Printing oemdata from mca uses data that is not passed through SAL, it is
+ * global.  Only one user at a time.
+ */
+static DECLARE_MUTEX(sn_oemdata_mutex);
+static u8 **sn_oemdata;
+static u64 *sn_oemdata_size, sn_oemdata_bufsize;
 
 /*
  * print_hook
  *
  * This function is the callback routine that SAL calls to log error
- * info for platform errors. 
+ * info for platform errors.  buf is appended to sn_oemdata, resizing as
+ * required.
  */
 static int
 print_hook(const char *fmt, ...)
 {
-	static int	newline=1;
-	char		buf[400], *p;
-	va_list		args;
-	int		len=0;
-
-
+	char buf[400];
+	int len;
+	va_list args;
 	va_start(args, fmt);
-	if (newline) {
-		strcpy(buf, "+ ");
-		len += 2;
-	}
-	len += vsnprintf(buf+len, sizeof(buf)-len, fmt, args);
-
-	/* Prefix each line with "+ " to be consistent with mca.c. */
-	p = buf;
-	while ((p=strchr(p, '\n')) && *++p != '\0') {
-		memmove(p+2, p, 1+strlen(p));
-		strncpy(p, "+ ", 2);
-		len += 2;
-	}
-	newline = (p != 0);
-
+	vsnprintf(buf, sizeof(buf), fmt, args);
 	va_end(args);
-	printk("%s", buf);
-	return len;
+	len = strlen(buf);
+	while (*sn_oemdata_size + len + 1 > sn_oemdata_bufsize) {
+		u8 *newbuf = vmalloc(sn_oemdata_bufsize += 1000);
+		if (!newbuf) {
+			printk(KERN_ERR "%s: unable to extend sn_oemdata\n", __FUNCTION__);
+			return 0;
+		}
+		memcpy(newbuf, *sn_oemdata, *sn_oemdata_size);
+		vfree(*sn_oemdata);
+		*sn_oemdata = newbuf;
+	}
+	memcpy(*sn_oemdata + *sn_oemdata_size, buf, len + 1);
+	*sn_oemdata_size += len;
+	return 0;
 }
 
 
@@ -95,6 +95,43 @@
 {
 	init_timer(&sn_cpei_timer);
 	sn_cpei_timer.expires = jiffies + CPEI_INTERVAL;
-        sn_cpei_timer.function = sn_cpei_timer_handler;
+	sn_cpei_timer.function = sn_cpei_timer_handler;
 	add_timer(&sn_cpei_timer);
 }
+
+static int
+sn_platform_plat_specific_err_print(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size)
+{
+	sal_log_plat_specific_err_info_t *psei = (sal_log_plat_specific_err_info_t *)sect_header;
+	if (!psei->valid.oem_data)
+		return 0;
+	down(&sn_oemdata_mutex);
+	sn_oemdata = oemdata;
+	sn_oemdata_size = oemdata_size;
+	sn_oemdata_bufsize = 0;
+	ia64_sn_plat_specific_err_print(print_hook, (char *)psei);
+	up(&sn_oemdata_mutex);
+	return 0;
+}
+
+/* Callback when userspace salinfo wants to decode oem data via the platform
+ * kernel and/or prom.
+ */
+int sn_salinfo_platform_oemdata(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size)
+{
+	efi_guid_t guid = *(efi_guid_t *)sect_header;
+	*oemdata_size = 0;
+	vfree(*oemdata);
+	*oemdata = NULL;
+	if (efi_guidcmp(guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0)
+		return sn_platform_plat_specific_err_print(sect_header, oemdata, oemdata_size);
+	return 0;
+}
+
+static int __init sn_salinfo_init(void)
+{
+	salinfo_platform_oemdata = &sn_salinfo_platform_oemdata;
+	return 0;
+}
+
+module_init(sn_salinfo_init)
diff -Nru a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
--- a/arch/ia64/sn/kernel/setup.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ia64/sn/kernel/setup.c	Sat Apr  3 19:38:42 2004
@@ -194,10 +194,7 @@
 	}
 }
 
-#ifdef CONFIG_IA64_MCA
 extern int platform_intr_list[];
-#endif
-
 extern nasid_t master_nasid;
 static int shub_1_1_found __initdata;
 
diff -Nru a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
--- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c	Sat Apr  3 19:38:56 2004
@@ -73,8 +73,13 @@
 	}
 }
 
-// Disable forced interrupts, but leave the code in, just in case.
-int sn_force_interrupt_flag = 0;
+/*
+ * Enable forced interrupt by default.
+ * When set, the sn interrupt handler writes the force interrupt register on
+ * the bridge chip.  The hardware will then send an interrupt message if the
+ * interrupt line is active.  This mimics a level sensitive interrupt.
+ */
+int sn_force_interrupt_flag = 1;
 
 static int
 sn_force_interrupt_read_proc(char *page, char **start, off_t off,
@@ -113,59 +118,11 @@
 	}
 }
 
-extern int sn_linkstats_get(char *);
-extern int sn_linkstats_reset(unsigned long);
-
-static int
-sn_linkstats_read_proc(char *page, char **start, off_t off,
-		int count, int *eof, void *data) {
-       
-	return sn_linkstats_get(page);
-}
-
-static int 
-sn_linkstats_write_proc(struct file *file, const char *buffer,
-                                        unsigned long count, void *data)
-{
-	char		s[64];
-	unsigned long	msecs;
-	int		e = count;
-
-	if (copy_from_user(s, buffer, count < sizeof(s) ? count : sizeof(s)))
-		e = -EFAULT;
-	else {
-		if (sscanf(s, "%lu", &msecs) != 1 || msecs < 5)
-			/* at least 5 milliseconds between updates */
-			e = -EINVAL;
-		else
-			sn_linkstats_reset(msecs);
-	}
-
-	return e;
-}
-
-void
-register_sn_linkstats(void) {
-	struct proc_dir_entry *entry;
-
-	if (!sgi_proc_dir) {
-		sgi_proc_dir = proc_mkdir("sgi_sn", 0);
-	}
-	entry = create_proc_entry("linkstats", 0444, sgi_proc_dir);
-	if (entry) {
-		entry->nlink = 1;
-		entry->data = 0;
-		entry->read_proc = sn_linkstats_read_proc;
-		entry->write_proc = sn_linkstats_write_proc;
-	}
-}
-
 void
 register_sn_procfs(void) {
 	register_sn_partition_id();
 	register_sn_serial_numbers();
 	register_sn_force_interrupt();
-	register_sn_linkstats();
 }
 
 #endif /* CONFIG_PROC_FS */
diff -Nru a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
--- a/arch/m68k/amiga/amiints.c	Sat Apr  3 19:38:57 2004
+++ b/arch/m68k/amiga/amiints.c	Sat Apr  3 19:38:57 2004
@@ -197,7 +197,7 @@
 	}
 
 	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 @@
 	}
 
 	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 -Nru a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c
--- a/arch/m68k/bvme6000/bvmeints.c	Sat Apr  3 19:38:41 2004
+++ b/arch/m68k/bvme6000/bvmeints.c	Sat Apr  3 19:38:41 2004
@@ -73,7 +73,7 @@
 	 */
 
 	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 @@
 	}
 #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 -Nru a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
--- a/arch/m68k/hp300/time.c	Sat Apr  3 19:38:54 2004
+++ b/arch/m68k/hp300/time.c	Sat Apr  3 19:38:54 2004
@@ -68,7 +68,7 @@
 
   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 -Nru a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
--- a/arch/m68k/kernel/entry.S	Sat Apr  3 19:38:40 2004
+++ b/arch/m68k/kernel/entry.S	Sat Apr  3 19:38:40 2004
@@ -528,7 +528,7 @@
 	.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 -Nru a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
--- a/arch/m68k/kernel/ints.c	Sat Apr  3 19:38:43 2004
+++ b/arch/m68k/kernel/ints.c	Sat Apr  3 19:38:43 2004
@@ -137,8 +137,8 @@
 
 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 @@
 	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 -Nru a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
--- a/arch/m68k/kernel/sys_m68k.c	Sat Apr  3 19:38:41 2004
+++ b/arch/m68k/kernel/sys_m68k.c	Sat Apr  3 19:38:41 2004
@@ -261,12 +261,6 @@
 	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 -Nru a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
--- a/arch/m68k/mac/iop.c	Sat Apr  3 19:38:55 2004
+++ b/arch/m68k/mac/iop.c	Sat Apr  3 19:38:55 2004
@@ -317,7 +317,7 @@
 {
 	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 -Nru a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
--- a/arch/m68k/mac/macints.c	Sat Apr  3 19:38:55 2004
+++ b/arch/m68k/mac/macints.c	Sat Apr  3 19:38:55 2004
@@ -261,7 +261,8 @@
 	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 @@
 #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 @@
 #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 -Nru a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
--- a/arch/m68k/mac/oss.c	Sat Apr  3 19:38:43 2004
+++ b/arch/m68k/mac/oss.c	Sat Apr  3 19:38:43 2004
@@ -67,15 +67,15 @@
 
 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 -Nru a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
--- a/arch/m68k/mac/psc.c	Sat Apr  3 19:38:44 2004
+++ b/arch/m68k/mac/psc.c	Sat Apr  3 19:38:44 2004
@@ -117,14 +117,10 @@
 
 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 -Nru a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
--- a/arch/m68k/mac/via.c	Sat Apr  3 19:38:43 2004
+++ b/arch/m68k/mac/via.c	Sat Apr  3 19:38:43 2004
@@ -260,24 +260,27 @@
 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 -Nru a/arch/m68k/mvme16x/16xints.c b/arch/m68k/mvme16x/16xints.c
--- a/arch/m68k/mvme16x/16xints.c	Sat Apr  3 19:38:55 2004
+++ b/arch/m68k/mvme16x/16xints.c	Sat Apr  3 19:38:55 2004
@@ -98,7 +98,7 @@
 		printk("%s: Removing probably wrong IRQ %d from %s\n",
 		       __FUNCTION__, irq, irq_tab[irq-64].devname);
 
-	irq_tab[irq-64].handler = mvme16x_defhand;;
+	irq_tab[irq-64].handler = mvme16x_defhand;
 	irq_tab[irq-64].flags   = IRQ_FLG_STD;
 	irq_tab[irq-64].dev_id  = NULL;
 	irq_tab[irq-64].devname = NULL;
diff -Nru a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
--- a/arch/m68k/q40/config.c	Sat Apr  3 19:38:43 2004
+++ b/arch/m68k/q40/config.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
     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 -Nru a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
--- a/arch/m68k/q40/q40ints.c	Sat Apr  3 19:38:55 2004
+++ b/arch/m68k/q40/q40ints.c	Sat Apr  3 19:38:55 2004
@@ -46,10 +46,8 @@
 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 @@
 	}
 
 	/* 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 @@
 	  }
 	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 @@
 	  }
 	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 @@
 	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 -Nru a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
--- a/arch/m68k/sun3/sun3ints.c	Sat Apr  3 19:38:56 2004
+++ b/arch/m68k/sun3/sun3ints.c	Sat Apr  3 19:38:56 2004
@@ -153,8 +153,8 @@
 	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 @@
 		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 -Nru a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c
--- a/arch/m68knommu/kernel/sys_m68k.c	Sat Apr  3 19:38:55 2004
+++ b/arch/m68knommu/kernel/sys_m68k.c	Sat Apr  3 19:38:55 2004
@@ -193,12 +193,6 @@
 	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 -Nru a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S
--- a/arch/m68knommu/kernel/syscalltable.S	Sat Apr  3 19:38:40 2004
+++ b/arch/m68knommu/kernel/syscalltable.S	Sat Apr  3 19:38:40 2004
@@ -120,7 +120,7 @@
 	.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 -Nru a/arch/mips/Kconfig b/arch/mips/Kconfig
--- a/arch/mips/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/mips/Kconfig	Sat Apr  3 19:38:43 2004
@@ -1209,9 +1209,8 @@
 	  People using multiprocessor machines who say Y here should also say
 	  Y to "Enhanced Real Time Clock Support", below.
 
-	  See also the <file:Documentation/smp.tex>,
-	  <file:Documentation/smp.txt> and the SMP-HOWTO available at
-	  <http://www.tldp.org/docs.html#howto>.
+	  See also the <file:Documentation/smp.txt> and the SMP-HOWTO
+	  available at <http://www.tldp.org/docs.html#howto>.
 
 	  If you don't know what to do here, say N.
 
diff -Nru a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig
--- a/arch/mips/configs/capcella_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/mips/configs/capcella_defconfig	Sat Apr  3 19:38:41 2004
@@ -196,7 +196,6 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig
--- a/arch/mips/configs/cobalt_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/mips/configs/cobalt_defconfig	Sat Apr  3 19:38:42 2004
@@ -189,7 +189,6 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
--- a/arch/mips/configs/db1500_defconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/mips/configs/db1500_defconfig	Sat Apr  3 19:38:43 2004
@@ -268,7 +268,6 @@
 CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/ddb5476_defconfig b/arch/mips/configs/ddb5476_defconfig
--- a/arch/mips/configs/ddb5476_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/mips/configs/ddb5476_defconfig	Sat Apr  3 19:38:42 2004
@@ -188,7 +188,6 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig
--- a/arch/mips/configs/e55_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/mips/configs/e55_defconfig	Sat Apr  3 19:38:42 2004
@@ -188,7 +188,6 @@
 CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/eagle_defconfig b/arch/mips/configs/eagle_defconfig
--- a/arch/mips/configs/eagle_defconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/mips/configs/eagle_defconfig	Sat Apr  3 19:38:40 2004
@@ -273,7 +273,6 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/hp-lj_defconfig b/arch/mips/configs/hp-lj_defconfig
--- a/arch/mips/configs/hp-lj_defconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/mips/configs/hp-lj_defconfig	Sat Apr  3 19:38:43 2004
@@ -245,7 +245,6 @@
 CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/it8172_defconfig b/arch/mips/configs/it8172_defconfig
--- a/arch/mips/configs/it8172_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/mips/configs/it8172_defconfig	Sat Apr  3 19:38:41 2004
@@ -243,7 +243,6 @@
 CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/ivr_defconfig b/arch/mips/configs/ivr_defconfig
--- a/arch/mips/configs/ivr_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/mips/configs/ivr_defconfig	Sat Apr  3 19:38:41 2004
@@ -191,7 +191,6 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig
--- a/arch/mips/configs/lasat200_defconfig	Sat Apr  3 19:38:44 2004
+++ b/arch/mips/configs/lasat200_defconfig	Sat Apr  3 19:38:44 2004
@@ -284,7 +284,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
--- a/arch/mips/configs/pb1500_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/mips/configs/pb1500_defconfig	Sat Apr  3 19:38:42 2004
@@ -251,7 +251,6 @@
 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
 
 #
diff -Nru a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
--- a/arch/mips/configs/rm200_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/mips/configs/rm200_defconfig	Sat Apr  3 19:38:42 2004
@@ -323,7 +323,6 @@
 # CONFIG_MD_RAID6 is not set
 CONFIG_MD_MULTIPATH=m
 CONFIG_BLK_DEV_DM=m
-CONFIG_DM_IOCTL_V4=y
 
 #
 # Fusion MPT device support
diff -Nru a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig
--- a/arch/mips/configs/tb0226_defconfig	Sat Apr  3 19:38:44 2004
+++ b/arch/mips/configs/tb0226_defconfig	Sat Apr  3 19:38:44 2004
@@ -192,7 +192,6 @@
 CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig
--- a/arch/mips/configs/workpad_defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/mips/configs/workpad_defconfig	Sat Apr  3 19:38:55 2004
@@ -188,7 +188,6 @@
 CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
--- a/arch/mips/kernel/sysirix.c	Sat Apr  3 19:38:55 2004
+++ b/arch/mips/kernel/sysirix.c	Sat Apr  3 19:38:55 2004
@@ -1249,9 +1249,9 @@
 	ks.st_atime.tv_sec = (s32) stat->atime.tv_sec;
 	ks.st_atime.tv_nsec = stat->atime.tv_nsec;
 	ks.st_mtime.tv_sec = (s32) stat->mtime.tv_sec;
-	ks.st_mtime.tv_nsec = stat->mtime.tv_nsec;;
+	ks.st_mtime.tv_nsec = stat->mtime.tv_nsec;
 	ks.st_ctime.tv_sec = (s32) stat->ctime.tv_sec;
-	ks.st_ctime.tv_nsec = stat->ctime.tv_nsec;;
+	ks.st_ctime.tv_nsec = stat->ctime.tv_nsec;
 
 	ks.st_blksize = (s32) stat->blksize;
 	ks.st_blocks = (long long) stat->blocks;
diff -Nru a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c
--- a/arch/mips/mm/dma-coherent.c	Sat Apr  3 19:38:42 2004
+++ b/arch/mips/mm/dma-coherent.c	Sat Apr  3 19:38:42 2004
@@ -119,30 +119,55 @@
 
 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 @@
 
 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 -Nru a/arch/mips/mm/dma-ip27.c b/arch/mips/mm/dma-ip27.c
--- a/arch/mips/mm/dma-ip27.c	Sat Apr  3 19:38:54 2004
+++ b/arch/mips/mm/dma-ip27.c	Sat Apr  3 19:38:54 2004
@@ -125,30 +125,55 @@
 
 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 @@
 
 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 -Nru a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c
--- a/arch/mips/mm/dma-noncoherent.c	Sat Apr  3 19:38:41 2004
+++ b/arch/mips/mm/dma-noncoherent.c	Sat Apr  3 19:38:41 2004
@@ -226,7 +226,7 @@
 
 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 @@
 	__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 @@
 	__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 @@
 		           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 @@
 
 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 @@
 	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 -Nru a/arch/parisc/Kconfig b/arch/parisc/Kconfig
--- a/arch/parisc/Kconfig	Sat Apr  3 19:38:44 2004
+++ b/arch/parisc/Kconfig	Sat Apr  3 19:38:44 2004
@@ -131,10 +131,9 @@
 	  singleprocessor machines. On a singleprocessor machine, the kernel
 	  will run faster if you say N here.
 
-	  See also the <file:Documentation/smp.tex>,
-	  <file:Documentation/smp.txt>, <file:Documentation/nmi_watchdog.txt>
-	  and the SMP-HOWTO available at
-	  <http://www.tldp.org/docs.html#howto>.
+	  See also the <file:Documentation/smp.txt>,
+	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available
+	  at <http://www.tldp.org/docs.html#howto>.
 
 	  If you don't know what to do here, say N.
 
diff -Nru a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig
--- a/arch/parisc/configs/712_defconfig	Sat Apr  3 19:38:56 2004
+++ b/arch/parisc/configs/712_defconfig	Sat Apr  3 19:38:56 2004
@@ -22,6 +22,7 @@
 # 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_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_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 @@
 #
 # Generic Driver Options
 #
+CONFIG_DEBUG_DRIVER=y
 
 #
 # Memory Technology Devices (MTD)
@@ -99,7 +101,6 @@
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -110,7 +111,6 @@
 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 @@
 #
 # 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 @@
 #
 # 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 @@
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -318,8 +325,8 @@
 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_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_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_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 @@
 #
 # 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 @@
 #
 
 #
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -511,7 +516,6 @@
 #
 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 @@
 #
 # 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_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_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 -Nru a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig
--- a/arch/parisc/configs/a500_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/parisc/configs/a500_defconfig	Sat Apr  3 19:38:41 2004
@@ -23,6 +23,7 @@
 # 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_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 @@
 # Generic Driver Options
 #
 # CONFIG_FW_LOADER is not set
+CONFIG_DEBUG_DRIVER=y
 
 #
 # Memory Technology Devices (MTD)
@@ -116,7 +117,6 @@
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -195,9 +195,15 @@
 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_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_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 @@
 #
 # Network testing
 #
-# CONFIG_NET_PKTGEN is not set
+CONFIG_NET_PKTGEN=m
 CONFIG_NETDEVICES=y
 
 #
@@ -391,9 +401,10 @@
 #
 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_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_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_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 @@
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -602,25 +616,7 @@
 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_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 @@
 #
 # 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 @@
 # USB support
 #
 # CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
 # CONFIG_USB_GADGET is not set
 
 #
@@ -711,6 +719,7 @@
 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_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_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_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 -Nru a/arch/parisc/configs/b180_defconfig b/arch/parisc/configs/b180_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/parisc/configs/b180_defconfig	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig
--- a/arch/parisc/configs/c3000_defconfig	Sat Apr  3 19:38:44 2004
+++ b/arch/parisc/configs/c3000_defconfig	Sat Apr  3 19:38:44 2004
@@ -23,6 +23,7 @@
 # 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_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 @@
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=y
+CONFIG_DEBUG_DRIVER=y
 
 #
 # Memory Technology Devices (MTD)
@@ -128,7 +129,6 @@
 # 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 @@
 #
 # 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_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
@@ -186,7 +186,6 @@
 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
 
 #
@@ -252,11 +251,13 @@
 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 +281,9 @@
 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 +294,7 @@
 CONFIG_FUSION_CTL=m
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
@@ -302,6 +304,10 @@
 # CONFIG_I2O is not set
 
 #
+# Macintosh device drivers
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -457,6 +463,7 @@
 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 +481,7 @@
 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 +491,7 @@
 # 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 +580,7 @@
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -652,7 +661,8 @@
 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 +706,10 @@
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -716,6 +730,7 @@
 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 +746,6 @@
 #
 # 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 +837,6 @@
 # USB Imaging devices
 #
 CONFIG_USB_MDC800=m
-CONFIG_USB_SCANNER=m
 CONFIG_USB_MICROTEK=m
 CONFIG_USB_HPUSBSCSI=m
 
@@ -867,6 +880,10 @@
 # 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 +900,7 @@
 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 +930,6 @@
 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 +942,7 @@
 # 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 +1064,7 @@
 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 -Nru a/arch/parisc/defconfig b/arch/parisc/defconfig
--- a/arch/parisc/defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/parisc/defconfig	Sat Apr  3 19:38:41 2004
@@ -22,6 +22,7 @@
 # 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_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_SUPERIO=y
 CONFIG_CHASSIS_LCD_LED=y
 CONFIG_PDC_CHASSIS=y
-# CONFIG_HOTPLUG is not set
 
 #
 # Executable file formats
@@ -86,6 +87,7 @@
 #
 # Generic Driver Options
 #
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -108,7 +110,6 @@
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -195,8 +196,16 @@
 # 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_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_FUSION is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
@@ -228,6 +238,10 @@
 # CONFIG_I2O is not set
 
 #
+# Macintosh device drivers
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -319,6 +333,7 @@
 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_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_AIRO=y
 # CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
 CONFIG_NET_WIRELESS=y
 
 #
@@ -419,7 +436,7 @@
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
 # Telephony Support
@@ -450,10 +467,10 @@
 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_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_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_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_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 @@
 # 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 @@
 #
 # 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 @@
 # 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 @@
 #
 # 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_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_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_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_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_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 -Nru a/arch/parisc/hpux/entry_hpux.S b/arch/parisc/hpux/entry_hpux.S
--- a/arch/parisc/hpux/entry_hpux.S	Sat Apr  3 19:38:42 2004
+++ b/arch/parisc/hpux/entry_hpux.S	Sat Apr  3 19:38:42 2004
@@ -1,10 +1,22 @@
-/*
+/*    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>
diff -Nru a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
--- a/arch/parisc/kernel/drivers.c	Sat Apr  3 19:38:55 2004
+++ b/arch/parisc/kernel/drivers.c	Sat Apr  3 19:38:55 2004
@@ -618,6 +618,7 @@
 		 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 -Nru a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
--- a/arch/parisc/kernel/entry.S	Sat Apr  3 19:38:42 2004
+++ b/arch/parisc/kernel/entry.S	Sat Apr  3 19:38:42 2004
@@ -533,7 +533,7 @@
 	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 -Nru a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
--- a/arch/parisc/kernel/hardware.c	Sat Apr  3 19:38:43 2004
+++ b/arch/parisc/kernel/hardware.c	Sat Apr  3 19:38:43 2004
@@ -333,8 +333,9 @@
 	{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 -Nru a/arch/parisc/kernel/head64.S b/arch/parisc/kernel/head64.S
--- a/arch/parisc/kernel/head64.S	Sat Apr  3 19:38:40 2004
+++ b/arch/parisc/kernel/head64.S	Sat Apr  3 19:38:40 2004
@@ -165,9 +165,9 @@
 #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 @@
 
 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 @@
 	/*  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 -Nru a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
--- a/arch/parisc/kernel/module.c	Sat Apr  3 19:38:57 2004
+++ b/arch/parisc/kernel/module.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
--- a/arch/parisc/kernel/pacache.S	Sat Apr  3 19:38:41 2004
+++ b/arch/parisc/kernel/pacache.S	Sat Apr  3 19:38:41 2004
@@ -221,6 +221,7 @@
 	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 @@
 
 fisync:
 	sync
+	mtsm	%r22
 	bv      %r0(%r2)
 	nop
 	.exit
diff -Nru a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
--- a/arch/parisc/kernel/parisc_ksyms.c	Sat Apr  3 19:38:56 2004
+++ b/arch/parisc/kernel/parisc_ksyms.c	Sat Apr  3 19:38:56 2004
@@ -67,8 +67,10 @@
 #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 -Nru a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
--- a/arch/parisc/kernel/pci-dma.c	Sat Apr  3 19:38:55 2004
+++ b/arch/parisc/kernel/pci-dma.c	Sat Apr  3 19:38:55 2004
@@ -372,7 +372,7 @@
 ** 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 @@
 	/*
 	 * 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 @@
 	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 @@
 	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 @@
 	.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 @@
 	.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 -Nru a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
--- a/arch/parisc/kernel/pci.c	Sat Apr  3 19:38:40 2004
+++ b/arch/parisc/kernel/pci.c	Sat Apr  3 19:38:40 2004
@@ -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 @@
 	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 -Nru a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
--- a/arch/parisc/kernel/process.c	Sat Apr  3 19:38:56 2004
+++ b/arch/parisc/kernel/process.c	Sat Apr  3 19:38:56 2004
@@ -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 @@
 	  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 @@
 	 * 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 @@
 
 		/* 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 -Nru a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
--- a/arch/parisc/kernel/smp.c	Sat Apr  3 19:38:56 2004
+++ b/arch/parisc/kernel/smp.c	Sat Apr  3 19:38:56 2004
@@ -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 -Nru a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
--- a/arch/parisc/kernel/sys_parisc.c	Sat Apr  3 19:38:55 2004
+++ b/arch/parisc/kernel/sys_parisc.c	Sat Apr  3 19:38:55 2004
@@ -242,14 +242,6 @@
 	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 -Nru a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
--- a/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 19:38:42 2004
+++ b/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 19:38:42 2004
@@ -607,105 +607,6 @@
 	return error;
 }
 
-static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
-{
-	int i;
-	unsigned long page;
-	struct vm_area_struct *vma;
-
-	*kernel = 0;
-	if(!user)
-		return 0;
-	vma = find_vma(current->mm, (unsigned long)user);
-	if(!vma || (unsigned long)user < vma->vm_start)
-		return -EFAULT;
-	if(!(vma->vm_flags & VM_READ))
-		return -EFAULT;
-	i = vma->vm_end - (unsigned long) user;
-	if(PAGE_SIZE <= (unsigned long) i)
-		i = PAGE_SIZE - 1;
-	if(!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
-	if(copy_from_user((void *) page, user, i)) {
-		free_page(page);
-		return -EFAULT;
-	}
-	*kernel = page;
-	return 0;
-}
-
-#define SMBFS_NAME	"smbfs"
-#define NCPFS_NAME	"ncpfs"
-
-asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
-{
-	unsigned long type_page = 0;
-	unsigned long data_page = 0;
-	unsigned long dev_page = 0;
-	unsigned long dir_page = 0;
-	int err, is_smb, is_ncp;
-
-	is_smb = is_ncp = 0;
-
-	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
-	if (err)
-		goto out;
-
-	if (!type_page) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	is_smb = !strcmp((char *)type_page, SMBFS_NAME);
-	is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
-
-	err = copy_mount_stuff_to_kernel((const void *)(unsigned long)data, &data_page);
-	if (err)
-		goto type_out;
-
-	err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
-	if (err)
-		goto data_out;
-
-	err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
-	if (err)
-		goto dev_out;
-
-	if (!is_smb && !is_ncp) {
-		lock_kernel();
-		err = do_mount((char*)dev_page, (char*)dir_page,
-				(char*)type_page, new_flags, (char*)data_page);
-		unlock_kernel();
-	} else {
-		if (is_ncp)
-			panic("NCP mounts not yet supported 32/64 parisc");
-			/* do_ncp_super_data_conv((void *)data_page); */
-		else {
-			panic("SMB mounts not yet supported 32/64 parisc");
-			/* do_smb_super_data_conv((void *)data_page); */
-		}
-
-		lock_kernel();
-		err = do_mount((char*)dev_page, (char*)dir_page,
-				(char*)type_page, new_flags, (char*)data_page);
-		unlock_kernel();
-	}
-	free_page(dir_page);
-
-dev_out:
-	free_page(dev_page);
-
-data_out:
-	free_page(data_page);
-
-type_out:
-	free_page(type_page);
-
-out:
-	return err;
-}
-
-
 /* readv/writev stolen from mips64 */
 typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
 
diff -Nru a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
--- a/arch/parisc/kernel/syscall_table.S	Sat Apr  3 19:38:41 2004
+++ b/arch/parisc/kernel/syscall_table.S	Sat Apr  3 19:38:41 2004
@@ -84,7 +84,7 @@
 	ENTRY_DIFF(lseek)
 	ENTRY_SAME(getpid)		/* 20 */
 	/* the 'void * data' parameter may need re-packing in wide */
-	ENTRY_DIFF(mount)
+	ENTRY_COMP(mount)
 	/* concerned about struct sockaddr in wide/narrow */
 	/* ---> I think sockaddr is OK unless the compiler packs the struct */
 	/*      differently to align the char array */
diff -Nru a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
--- a/arch/parisc/kernel/vmlinux.lds.S	Sat Apr  3 19:38:41 2004
+++ b/arch/parisc/kernel/vmlinux.lds.S	Sat Apr  3 19:38:41 2004
@@ -61,6 +61,9 @@
   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 -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc/Kconfig	Sat Apr  3 19:38:56 2004
@@ -163,7 +163,7 @@
 	  fly. This is a nice method to save battery power on notebooks,
 	  because the lower the clock speed, the less power the CPU consumes.
 
-	  For more information, take a look at linux/Documentation/cpufreq or
+	  For more information, take a look at linux/Documentation/cpu-freq or
 	  at <http://www.brodo.de/cpufreq/>
 
 	  If in doubt, say N.
@@ -609,7 +609,7 @@
 
 config PPC_GEN550
 	bool
-	depends on SANDPOINT || MCPN765 || SPRUCE
+	depends on SANDPOINT || MCPN765 || SPRUCE || PPLUS
 	default y
 
 config FORCE
@@ -696,14 +696,10 @@
 
 config PREEMPT
 	bool "Preemptible Kernel"
-	depends on !SMP
 	help
 	  This option reduces the latency of the kernel when reacting to
 	  real-time or interactive events by allowing a low priority process to
 	  be preempted even if it is in kernel mode executing a system call.
-	  Unfortunately the kernel code has some race conditions if both
-	  CONFIG_SMP and CONFIG_PREEMPT are enabled, so this option is
-	  currently disabled if you are building an SMP kernel.
 
 	  Say Y here if you are building a kernel for a desktop, embedded
 	  or real-time system.  Say N if you are unsure.
diff -Nru a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
--- a/arch/ppc/boot/Makefile	Sat Apr  3 19:38:44 2004
+++ b/arch/ppc/boot/Makefile	Sat Apr  3 19:38:44 2004
@@ -16,13 +16,12 @@
 BOOT_TARGETS	= zImage zImage.initrd znetboot znetboot.initrd
 
 bootdir-y			:= simple
-bootdir-$(CONFIG_PPC_OF)	:= openfirmware
-bootdir-$(CONFIG_PPC_PREP)	+= prep
+bootdir-$(CONFIG_PPC_OF)	+= openfirmware
 subdir-y			:= lib/ common/ images/
 subdir-$(CONFIG_PPC_OF)		+= of1275/
 
 # for cleaning
-subdir-				+= simple/ openfirmware/ prep/
+subdir-				+= simple/ openfirmware/
 
 host-progs := $(addprefix utils/, addnote mknote hack-coff mkprep mkbugboot mktree)
 
diff -Nru a/arch/ppc/boot/common/Makefile b/arch/ppc/boot/common/Makefile
--- a/arch/ppc/boot/common/Makefile	Sat Apr  3 19:38:44 2004
+++ b/arch/ppc/boot/common/Makefile	Sat Apr  3 19:38:44 2004
@@ -9,8 +9,5 @@
 #
 
 lib-y					:= string.o util.o misc-common.o \
-						serial_stub.o
-lib-$(CONFIG_PPC_PREP)			+= mpc10x_memory.o
-lib-$(CONFIG_LOPEC)			+= mpc10x_memory.o
-lib-$(CONFIG_PAL4)			+= cpc700_memory.o
+						serial_stub.o bootinfo.o
 lib-$(CONFIG_SERIAL_8250_CONSOLE)	+= ns16550.o
diff -Nru a/arch/ppc/boot/common/cpc700_memory.c b/arch/ppc/boot/common/cpc700_memory.c
--- a/arch/ppc/boot/common/cpc700_memory.c	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-/*
- * arch/ppc/boot/common/cpc700_memory.c
- *
- * Find memory based upon settings in the CPC700 bridge
- *
- * Author: Dan Cox
- *
- * 2001-2002 (c) 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.
- */
-
-#include <asm/types.h>
-#include <asm/io.h>
-#include "cpc700.h"
-
-unsigned long
-cpc700_get_mem_size(void)
-{
-	int i;
-	unsigned long len, amt;
-
-	/* Start at MB1EA, since MB0EA will most likely be the ending address
-	   for ROM space. */
-	for(len = 0, i = CPC700_MB1EA; i <= CPC700_MB4EA; i+=4) {
-		amt = cpc700_read_memreg(i);
-		if (amt == 0)
-			break;
-		len = amt;
-	}
-
-	return len;
-}
-
-
diff -Nru a/arch/ppc/boot/common/mpc10x_memory.c b/arch/ppc/boot/common/mpc10x_memory.c
--- a/arch/ppc/boot/common/mpc10x_memory.c	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,107 +0,0 @@
-/*
- * arch/ppc/boot/common/mpc10x_common.c
- *
- * A routine to find out how much memory the machine has.
- *
- * Based on:
- * arch/ppc/kernel/mpc10x_common.c
- *
- * Author: Mark A. Greer
- *         mgreer@mvista.com
- *
- * 2001-2002 (c) 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.
- */
-
-#include <linux/pci.h>
-#include <asm/types.h>
-#include <asm/io.h>
-#include "mpc10x.h"
-
-/*
- * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
- */
-
-/*
- * PCI config space macros, similar to indirect_xxx and early_xxx macros.
- * We assume bus 0.
- */
-#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
-#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
-
-#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
-static void								\
-mpc10x_##rw##_config_##size(unsigned int *cfg_addr, 			\
-		unsigned int *cfg_data, int devfn, int offset,		\
-		type val)						\
-{									\
-	out_be32(cfg_addr, 						\
-		 ((offset & 0xfc) << 24) | (devfn << 16)		\
-		 | (0 << 8) | 0x80);					\
-	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
-	return;    					 		\
-}
-
-MPC10X_PCI_OP(read, byte,  u8 *, in_8, 3)
-MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0)
-
-/*
- * Read the memory controller registers to determine the amount of memory in
- * the system.  This assumes that the firmware has correctly set up the memory
- * controller registers.  On CONFIG_PPC_PREP, we know we are being called
- * under a PReP memory map. On all other machines, we assume we are under
- * a CHRP memory map.
- */
-unsigned long
-get_mem_size(void)
-{
-	unsigned int *config_addr, *config_data, val;
-	unsigned long start, end, total, offset;
-	int i;
-	unsigned char bank_enables;
-
-#ifdef CONFIG_PPC_PREP
-	config_addr = (unsigned int *)MPC10X_MAPA_CNFG_ADDR;
-	config_data = (unsigned int *)MPC10X_MAPA_CNFG_DATA;
-#else
-	config_addr = (unsigned int *)MPC10X_MAPB_CNFG_ADDR;
-	config_data = (unsigned int *)MPC10X_MAPB_CNFG_DATA;
-#endif
-
-	mpc10x_read_config_byte(config_addr, config_data, PCI_DEVFN(0,0),
-			MPC10X_MCTLR_MEM_BANK_ENABLES, &bank_enables);
-
-	total = 0;
-
-	for (i = 0; i < 8; i++) {
-		if (bank_enables & (1 << i)) {
-			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
-			mpc10x_read_config_dword(config_addr, config_data,
-					PCI_DEVFN(0,0), offset, &val);
-			start = (val >> ((i & 3) << 3)) & 0xff;
-
-			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
-			mpc10x_read_config_dword(config_addr, config_data,
-					PCI_DEVFN(0,0), offset, &val);
-			val = (val >> ((i & 3) << 3)) & 0x03;
-			start = (val << 28) | (start << 20);
-
-			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
-			mpc10x_read_config_dword(config_addr, config_data,
-					PCI_DEVFN(0,0), offset, &val);
-			end = (val >> ((i & 3) << 3)) & 0xff;
-
-			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
-			mpc10x_read_config_dword(config_addr, config_data,
-					PCI_DEVFN(0,0), offset, &val);
-			val = (val >> ((i & 3) << 3)) & 0x03;
-			end = (val << 28) | (end << 20) | 0xfffff;
-
-			total += (end - start + 1);
-		}
-	}
-
-	return total;
-}
diff -Nru a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S
--- a/arch/ppc/boot/common/util.S	Sat Apr  3 19:38:57 2004
+++ b/arch/ppc/boot/common/util.S	Sat Apr  3 19:38:57 2004
@@ -14,7 +14,7 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * 2001-2003 (c) MontaVista, Software, Inc.  This file is licensed under
+ * 2001-2004 (c) 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.
@@ -36,6 +36,13 @@
 	 */
 	li	r8,MSR_IP|MSR_FP
 	mtmsr	r8
+	isync
+
+	/* Test for a 601 */
+	mfpvr	r10
+	srwi	r10,r10,16
+	cmpi	0,r10,1		/* 601 ? */
+	beq	.clearbats_601
 
 	/* Clear BATs */
 	li	r8,0
@@ -47,6 +54,7 @@
 	mtspr	DBAT2L,r8
 	mtspr	DBAT3U,r8
 	mtspr	DBAT3L,r8
+.clearbats_601:
 	mtspr	IBAT0U,r8
 	mtspr	IBAT0L,r8
 	mtspr	IBAT1U,r8
@@ -68,6 +76,7 @@
 	addi	r8,r8,0x111	/* increment VSID */
 	addis	r10,r10,0x1000	/* address of next segment */
 	bdnz	3b
+	blr
 
 	.globl	disable_6xx_l1cache
 disable_6xx_l1cache:
diff -Nru a/arch/ppc/boot/include/iso_font.h b/arch/ppc/boot/include/iso_font.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/include/iso_font.h	Sat Apr  3 19:38:56 2004
@@ -0,0 +1,257 @@
+static const unsigned char font[] = {
+/* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
+/* 0x02 */ 0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00,
+/* 0x03 */ 0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,
+/* 0x04 */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* 0x05 */ 0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x06 */ 0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x07 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x08 */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+/* 0x09 */ 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,
+/* 0x0A */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF,
+/* 0x0B */ 0x00,0x00,0x3E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
+/* 0x0C */ 0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x0D */ 0x00,0x00,0x30,0x38,0x3C,0x36,0x33,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,
+/* 0x0E */ 0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00,
+/* 0x0F */ 0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x10 */ 0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,
+/* 0x11 */ 0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
+/* 0x12 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,
+/* 0x13 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
+/* 0x14 */ 0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,
+/* 0x15 */ 0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,
+/* 0x16 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,
+/* 0x17 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,
+/* 0x18 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x19 */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,
+/* 0x1A */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x1B */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x1C */ 0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x1D */ 0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x1E */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,
+/* 0x1F */ 0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* 0x20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x21 */ 0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x22 */ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x23 */ 0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,
+/* 0x24 */ 0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00,
+/* 0x25 */ 0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00,
+/* 0x26 */ 0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x27 */ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x28 */ 0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,
+/* 0x29 */ 0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,
+/* 0x2A */ 0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x2B */ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x2C */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
+/* 0x2D */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x2E */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x2F */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,
+/* 0x30 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+/* 0x31 */ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,
+/* 0x32 */ 0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00,
+/* 0x33 */ 0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x34 */ 0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,
+/* 0x35 */ 0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x36 */ 0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x37 */ 0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
+/* 0x38 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x39 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00,
+/* 0x3A */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/* 0x3B */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
+/* 0x3C */ 0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,
+/* 0x3D */ 0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x3E */ 0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
+/* 0x3F */ 0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x40 */ 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00,
+/* 0x41 */ 0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x42 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,
+/* 0x43 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00,
+/* 0x44 */ 0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00,
+/* 0x45 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
+/* 0x46 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+/* 0x47 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00,
+/* 0x48 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x49 */ 0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x4A */ 0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
+/* 0x4B */ 0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+/* 0x4C */ 0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
+/* 0x4D */ 0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x4E */ 0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x4F */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x50 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+/* 0x51 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00,
+/* 0x52 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+/* 0x53 */ 0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x54 */ 0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x55 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x56 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00,
+/* 0x57 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00,
+/* 0x58 */ 0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x59 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x5A */ 0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00,
+/* 0x5B */ 0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,
+/* 0x5C */ 0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
+/* 0x5D */ 0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,
+/* 0x5E */ 0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x5F */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,
+/* 0x60 */ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x61 */ 0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x62 */ 0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,
+/* 0x63 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x64 */ 0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x65 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x66 */ 0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+/* 0x67 */ 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,
+/* 0x68 */ 0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+/* 0x69 */ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x6A */ 0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,
+/* 0x6B */ 0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00,
+/* 0x6C */ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x6D */ 0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xD6,0xD6,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x6E */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/* 0x6F */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x70 */ 0x00,0x00,0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,
+/* 0x71 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00,
+/* 0x72 */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+/* 0x73 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x74 */ 0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,
+/* 0x75 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x76 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,
+/* 0x77 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00,
+/* 0x78 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,
+/* 0x79 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00,
+/* 0x7A */ 0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
+/* 0x7B */ 0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,
+/* 0x7C */ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x7D */ 0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
+/* 0x7E */ 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x7F */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,
+/* 0x80 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00,
+/* 0x81 */ 0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x82 */ 0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x83 */ 0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x84 */ 0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x85 */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x86 */ 0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x87 */ 0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00,
+/* 0x88 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x89 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x8A */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x8B */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x8C */ 0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x8D */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x8E */ 0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x8F */ 0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x90 */ 0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00,
+/* 0x91 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00,
+/* 0x92 */ 0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00,
+/* 0x93 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x94 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x95 */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x96 */ 0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x97 */ 0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x98 */ 0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
+/* 0x99 */ 0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x9A */ 0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x9B */ 0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x9C */ 0x00,0x38,0x6C,0x64,0x60,0xF8,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00,
+/* 0x9D */ 0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x9E */ 0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00,
+/* 0x9F */ 0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00,
+/* 0xA0 */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0xA1 */ 0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0xA2 */ 0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0xA3 */ 0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0xA4 */ 0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/* 0xA5 */ 0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0xA6 */ 0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xA7 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xA8 */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0xA9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,
+/* 0xAA */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
+/* 0xAB */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00,
+/* 0xAC */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00,
+/* 0xAD */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,
+/* 0xAE */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xAF */ 0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xB0 */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
+/* 0xB1 */ 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
+/* 0xB2 */ 0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,
+/* 0xB3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xB4 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xB5 */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xB6 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xB7 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xB8 */ 0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xB9 */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xBA */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xBB */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xBC */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xBD */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xBE */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xBF */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xC1 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xC2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC4 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xC5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC6 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xC8 */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xC9 */ 0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xCA */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xCB */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xCC */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xCD */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xCE */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xCF */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xD0 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xD1 */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xD2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xD3 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xD4 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xD5 */ 0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xD6 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xD7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xD8 */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xD9 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xDA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xDB */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+/* 0xDC */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+/* 0xDD */ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
+/* 0xDE */ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+/* 0xDF */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xE0 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00,
+/* 0xE1 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xFC,0xC6,0xC6,0xC6,0xC6,0xDC,0xC0,0xC0,0x00,0x00,
+/* 0xE2 */ 0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,
+/* 0xE3 */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,
+/* 0xE4 */ 0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
+/* 0xE5 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
+/* 0xE6 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0xC0,0x00,0x00,0x00,
+/* 0xE7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0xE8 */ 0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,
+/* 0xE9 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+/* 0xEA */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00,
+/* 0xEB */ 0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,
+/* 0xEC */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xED */ 0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00,
+/* 0xEE */ 0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00,
+/* 0xEF */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0xF0 */ 0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,
+/* 0xF1 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,
+/* 0xF2 */ 0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00,
+/* 0xF3 */ 0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00,
+/* 0xF4 */ 0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xF5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
+/* 0xF6 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/* 0xF7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xF8 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xF9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xFA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xFB */ 0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00,
+/* 0xFC */ 0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xFD */ 0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xFE */ 0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,
+};
diff -Nru a/arch/ppc/boot/ld.script b/arch/ppc/boot/ld.script
--- a/arch/ppc/boot/ld.script	Sat Apr  3 19:38:45 2004
+++ b/arch/ppc/boot/ld.script	Sat Apr  3 19:38:45 2004
@@ -82,6 +82,7 @@
     *(__ksymtab)
     *(__ksymtab_strings)
     *(__bug_table)
+    *(__kcrctab)
   }
 
 }
diff -Nru a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile
--- a/arch/ppc/boot/lib/Makefile	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/boot/lib/Makefile	Sat Apr  3 19:38:55 2004
@@ -2,4 +2,7 @@
 # Makefile for some libs needed by zImage.
 #
 
+CFLAGS_kbd.o	+= -Idrivers/char
+
 lib-y := zlib.o div64.o
+lib-$(CONFIG_VGA_CONSOLE) += vreset.o kbd.o
diff -Nru a/arch/ppc/boot/lib/kbd.c b/arch/ppc/boot/lib/kbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/lib/kbd.c	Sat Apr  3 19:38:41 2004
@@ -0,0 +1,248 @@
+#include <linux/keyboard.h>
+
+#include "defkeymap.c"	/* yeah I know it's bad -- Cort */
+
+
+unsigned char shfts, ctls, alts, caps;
+
+#define	KBDATAP		0x60	/* kbd data port */
+#define	KBSTATUSPORT	0x61	/* kbd status */
+#define	KBSTATP		0x64	/* kbd status port */
+#define	KBINRDY		0x01
+#define	KBOUTRDY	0x02
+
+extern unsigned char inb(int port);
+extern void outb(int port, char val);
+extern void puts(const char *);
+extern void puthex(unsigned long val);
+extern void udelay(long x);
+
+static int kbd(int noblock)
+{
+	unsigned char dt, brk, val;
+	unsigned code;
+loop:
+	if (noblock) {
+	    if ((inb(KBSTATP) & KBINRDY) == 0)
+		return (-1);
+	} else while((inb(KBSTATP) & KBINRDY) == 0) ;
+
+	dt = inb(KBDATAP);
+
+	brk = dt & 0x80;	/* brk == 1 on key release */
+	dt = dt & 0x7f;		/* keycode */
+
+	if (shfts)
+	    code = shift_map[dt];
+	else if (ctls)
+	    code = ctrl_map[dt];
+	else
+	    code = plain_map[dt];
+
+	val = KVAL(code);
+	switch (KTYP(code) & 0x0f) {
+	    case KT_LATIN:
+		if (brk)
+		    break;
+		if (alts)
+		    val |= 0x80;
+		if (val == 0x7f)	/* map delete to backspace */
+		    val = '\b';
+		return val;
+
+	    case KT_LETTER:
+		if (brk)
+		    break;
+		if (caps)
+		    val -= 'a'-'A';
+		return val;
+
+	    case KT_SPEC:
+		if (brk)
+		    break;
+		if (val == KVAL(K_CAPS))
+		    caps = !caps;
+		else if (val == KVAL(K_ENTER)) {
+enter:		    /* Wait for key up */
+		    while (1) {
+			while((inb(KBSTATP) & KBINRDY) == 0) ;
+			dt = inb(KBDATAP);
+			if (dt & 0x80) /* key up */ break;
+		    }
+		    return 10;
+		}
+		break;
+
+	    case KT_PAD:
+		if (brk)
+		    break;
+		if (val < 10)
+		    return val;
+		if (val == KVAL(K_PENTER))
+		    goto enter;
+		break;
+
+	    case KT_SHIFT:
+		switch (val) {
+		    case KG_SHIFT:
+		    case KG_SHIFTL:
+		    case KG_SHIFTR:
+			shfts = brk ? 0 : 1;
+			break;
+		    case KG_ALT:
+		    case KG_ALTGR:
+			alts = brk ? 0 : 1;
+			break;
+		    case KG_CTRL:
+		    case KG_CTRLL:
+		    case KG_CTRLR:
+			ctls = brk ? 0 : 1;
+			break;
+		}
+		break;
+
+	    case KT_LOCK:
+		switch (val) {
+		    case KG_SHIFT:
+		    case KG_SHIFTL:
+		    case KG_SHIFTR:
+			if (brk)
+			    shfts = !shfts;
+			break;
+		    case KG_ALT:
+		    case KG_ALTGR:
+			if (brk)
+			    alts = !alts;
+			break;
+		    case KG_CTRL:
+		    case KG_CTRLL:
+		    case KG_CTRLR:
+			if (brk)
+			    ctls = !ctls;
+			break;
+		}
+		break;
+	}
+	if (brk) return (-1);  /* Ignore initial 'key up' codes */
+	goto loop;
+}
+
+static int __kbdreset(void)
+{
+	unsigned char c;
+	int i, t;
+
+	/* flush input queue */
+	t = 2000;
+	while ((inb(KBSTATP) & KBINRDY))
+	{
+		(void)inb(KBDATAP);
+		if (--t == 0)
+			return 1;
+	}
+	/* Send self-test */
+	t = 20000;
+	while (inb(KBSTATP) & KBOUTRDY)
+		if (--t == 0)
+			return 2;
+	outb(KBSTATP,0xAA);
+	t = 200000;
+	while ((inb(KBSTATP) & KBINRDY) == 0)	/* wait input ready */
+		if (--t == 0)
+			return 3;
+	if ((c = inb(KBDATAP)) != 0x55)
+	{
+		puts("Keyboard self test failed - result:");
+		puthex(c);
+		puts("\n");
+	}
+	/* Enable interrupts and keyboard controller */
+	t = 20000;
+	while (inb(KBSTATP) & KBOUTRDY)
+		if (--t == 0) return 4;
+	outb(KBSTATP,0x60);
+	t = 20000;
+	while (inb(KBSTATP) & KBOUTRDY)
+		if (--t == 0) return 5;
+	outb(KBDATAP,0x45);
+	for (i = 0;  i < 10000;  i++) udelay(1);
+
+	t = 20000;
+	while (inb(KBSTATP) & KBOUTRDY)
+		if (--t == 0) return 6;
+	outb(KBSTATP,0x20);
+	t = 200000;
+	while ((inb(KBSTATP) & KBINRDY) == 0)	/* wait input ready */
+		if (--t == 0) return 7;
+	if (! (inb(KBDATAP) & 0x40)) {
+		/*
+		 * Quote from PS/2 System Reference Manual:
+		 *
+		 * "Address hex 0060 and address hex 0064 should be
+		 * written only when the input-buffer-full bit and
+		 * output-buffer-full bit in the Controller Status
+		 * register are set 0." (KBINRDY and KBOUTRDY)
+		 */
+		t = 200000;
+		while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
+			if (--t == 0) return 8;
+		outb(KBDATAP,0xF0);
+		t = 200000;
+		while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
+			if (--t == 0) return 9;
+		outb(KBDATAP,0x01);
+	}
+	t = 20000;
+	while (inb(KBSTATP) & KBOUTRDY)
+		if (--t == 0) return 10;
+	outb(KBSTATP,0xAE);
+	return 0;
+}
+
+static void kbdreset(void)
+{
+	int ret = __kbdreset();
+
+	if (ret) {
+		puts("__kbdreset failed: ");
+		puthex(ret);
+		puts("\n");
+	}
+}
+
+/* We have to actually read the keyboard when CRT_tstc is called,
+ * since the pending data might be a key release code, and therefore
+ * not valid data.  In this case, kbd() will return -1, even though there's
+ * data to be read.  Of course, we might actually read a valid key press,
+ * in which case it gets queued into key_pending for use by CRT_getc.
+ */
+
+static int kbd_reset = 0;
+
+static int key_pending = -1;
+
+int CRT_getc(void)
+{
+	int c;
+	if (!kbd_reset) {kbdreset(); kbd_reset++; }
+
+        if (key_pending != -1) {
+                c = key_pending;
+                key_pending = -1;
+                return c;
+        } else {
+	while ((c = kbd(0)) == 0) ;
+                return c;
+        }
+}
+
+int CRT_tstc(void)
+{
+	if (!kbd_reset) {kbdreset(); kbd_reset++; }
+
+        while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) {
+                key_pending = kbd(1);
+        }
+
+        return (key_pending != -1);
+}
diff -Nru a/arch/ppc/boot/lib/vreset.c b/arch/ppc/boot/lib/vreset.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/lib/vreset.c	Sat Apr  3 19:38:40 2004
@@ -0,0 +1,805 @@
+/*
+ * vreset.c
+ *
+ * Initialize the VGA control registers to 80x25 text mode.
+ *
+ * Adapted from a program by:
+ *                                      Steve Sellgren
+ *                                      San Francisco Indigo Company
+ *                                      sfindigo!sellgren@uunet.uu.net
+ *
+ * Original concept by:
+ *                                      Gary Thomas <gdt@linuxppc.org>
+ * Adapted for Moto boxes by:
+ *                                      Pat Kane & Mark Scott, 1996
+ * Adapted for IBM portables by:
+ *                                      Takeshi Ishimoto
+ * Multi-console support:
+ *                                      Terje Malmedal <terje.malmedal@usit.uio.no>
+ */
+
+#include "iso_font.h"
+#include "nonstdio.h"
+
+extern char *vidmem;
+extern int lines, cols;
+struct VaRegs;
+
+/*
+ * VGA Register
+ */
+struct VgaRegs
+{
+	unsigned short io_port;
+	unsigned char  io_index;
+	unsigned char  io_value;
+};
+
+void unlockVideo(int slot);
+void setTextRegs(struct VgaRegs *svp);
+void setTextCLUT(int shift);
+void clearVideoMemory(void);
+void loadFont(unsigned char *ISA_mem);
+
+static void mdelay(int ms)
+{
+	for (; ms > 0; --ms)
+		udelay(1000);
+}
+
+/*
+ * Default console text mode registers  used to reset
+ * graphics adapter.
+ */
+#define NREGS 54
+#define ENDMK  0xFFFF  /* End marker */
+
+#define S3Vendor	0x5333
+#define CirrusVendor    0x1013
+#define DiamondVendor   0x100E
+#define MatroxVendor    0x102B
+#define ParadiseVendor  0x101C
+
+struct VgaRegs GenVgaTextRegs[NREGS+1] = {
+	/* port		index	value  */
+	/* SR Regs */
+	{ 0x3c4,	0x1,	0x0 },
+	{ 0x3c4,	0x2,	0x3 },
+	{ 0x3c4,	0x3,	0x0 },
+	{ 0x3c4,	0x4,	0x2 },
+	 /* CR Regs */
+	{ 0x3d4,	0x0,	0x5f },
+	{ 0x3d4,	0x1,	0x4f },
+	{ 0x3d4,	0x2,	0x50 },
+	{ 0x3d4,	0x3,	0x82 },
+	{ 0x3d4,	0x4,	0x55 },
+	{ 0x3d4,	0x5,	0x81 },
+	{ 0x3d4,	0x6,	0xbf },
+	{ 0x3d4,	0x7,	0x1f },
+	{ 0x3d4,	0x8,	0x00 },
+	{ 0x3d4,	0x9,	0x4f },
+	{ 0x3d4,	0xa,	0x0d },
+	{ 0x3d4,	0xb,	0x0e },
+	{ 0x3d4,	0xc,	0x00 },
+	{ 0x3d4,	0xd,	0x00 },
+	{ 0x3d4,	0xe,	0x00 },
+	{ 0x3d4,	0xf,	0x00 },
+	{ 0x3d4,	0x10,	0x9c },
+	{ 0x3d4,	0x11,	0x8e },
+	{ 0x3d4,	0x12,	0x8f },
+	{ 0x3d4,	0x13,	0x28 },
+	{ 0x3d4,	0x14,	0x1f },
+	{ 0x3d4,	0x15,	0x96 },
+	{ 0x3d4,	0x16,	0xb9 },
+	{ 0x3d4,	0x17,	0xa3 },
+	 /* GR Regs */
+	{ 0x3ce,	0x0,	0x0 },
+	{ 0x3ce,	0x1,	0x0 },
+	{ 0x3ce,	0x2,	0x0 },
+	{ 0x3ce,	0x3,	0x0 },
+	{ 0x3ce,	0x4,	0x0 },
+	{ 0x3ce,	0x5,	0x10 },
+	{ 0x3ce,	0x6,	0xe },
+	{ 0x3ce,	0x7,	0x0 },
+	{ 0x3ce,	0x8,	0xff },
+	{ ENDMK }
+};
+
+struct RGBColors
+{
+  unsigned char r, g, b;
+};
+
+/*
+ * Default console text mode color table.
+ * These values were obtained by booting Linux with
+ * text mode firmware & then dumping the registers.
+ */
+struct RGBColors TextCLUT[256] =
+{
+	/* red	green	blue  */
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x2a },
+	{ 0x0,	0x2a,	0x0 },
+	{ 0x0,	0x2a,	0x2a },
+	{ 0x2a,	0x0,	0x0 },
+	{ 0x2a,	0x0,	0x2a },
+	{ 0x2a,	0x2a,	0x0 },
+	{ 0x2a,	0x2a,	0x2a },
+	{ 0x0,	0x0,	0x15 },
+	{ 0x0,	0x0,	0x3f },
+	{ 0x0,	0x2a,	0x15 },
+	{ 0x0,	0x2a,	0x3f },
+	{ 0x2a,	0x0,	0x15 },
+	{ 0x2a,	0x0,	0x3f },
+	{ 0x2a,	0x2a,	0x15 },
+	{ 0x2a,	0x2a,	0x3f },
+	{ 0x0,	0x15,	0x0 },
+	{ 0x0,	0x15,	0x2a },
+	{ 0x0,	0x3f,	0x0 },
+	{ 0x0,	0x3f,	0x2a },
+	{ 0x2a,	0x15,	0x0 },
+	{ 0x2a,	0x15,	0x2a },
+	{ 0x2a,	0x3f,	0x0 },
+	{ 0x2a,	0x3f,	0x2a },
+	{ 0x0,	0x15,	0x15 },
+	{ 0x0,	0x15,	0x3f },
+	{ 0x0,	0x3f,	0x15 },
+	{ 0x0,	0x3f,	0x3f },
+	{ 0x2a,	0x15,	0x15 },
+	{ 0x2a,	0x15,	0x3f },
+	{ 0x2a,	0x3f,	0x15 },
+	{ 0x2a,	0x3f,	0x3f },
+	{ 0x15,	0x0,	0x0 },
+	{ 0x15,	0x0,	0x2a },
+	{ 0x15,	0x2a,	0x0 },
+	{ 0x15,	0x2a,	0x2a },
+	{ 0x3f,	0x0,	0x0 },
+	{ 0x3f,	0x0,	0x2a },
+	{ 0x3f,	0x2a,	0x0 },
+	{ 0x3f,	0x2a,	0x2a },
+	{ 0x15,	0x0,	0x15 },
+	{ 0x15,	0x0,	0x3f },
+	{ 0x15,	0x2a,	0x15 },
+	{ 0x15,	0x2a,	0x3f },
+	{ 0x3f,	0x0,	0x15 },
+	{ 0x3f,	0x0,	0x3f },
+	{ 0x3f,	0x2a,	0x15 },
+	{ 0x3f,	0x2a,	0x3f },
+	{ 0x15,	0x15,	0x0 },
+	{ 0x15,	0x15,	0x2a },
+	{ 0x15,	0x3f,	0x0 },
+	{ 0x15,	0x3f,	0x2a },
+	{ 0x3f,	0x15,	0x0 },
+	{ 0x3f,	0x15,	0x2a },
+	{ 0x3f,	0x3f,	0x0 },
+	{ 0x3f,	0x3f,	0x2a },
+	{ 0x15,	0x15,	0x15 },
+	{ 0x15,	0x15,	0x3f },
+	{ 0x15,	0x3f,	0x15 },
+	{ 0x15,	0x3f,	0x3f },
+	{ 0x3f,	0x15,	0x15 },
+	{ 0x3f,	0x15,	0x3f },
+	{ 0x3f,	0x3f,	0x15 },
+	{ 0x3f,	0x3f,	0x3f },
+	{ 0x39,	0xc,	0x5 },
+	{ 0x15,	0x2c,	0xf },
+	{ 0x26,	0x10,	0x3d },
+	{ 0x29,	0x29,	0x38 },
+	{ 0x4,	0x1a,	0xe },
+	{ 0x2,	0x1e,	0x3a },
+	{ 0x3c,	0x25,	0x33 },
+	{ 0x3c,	0xc,	0x2c },
+	{ 0x3f,	0x3,	0x2b },
+	{ 0x1c,	0x9,	0x13 },
+	{ 0x25,	0x2a,	0x35 },
+	{ 0x1e,	0xa,	0x38 },
+	{ 0x24,	0x8,	0x3 },
+	{ 0x3,	0xe,	0x36 },
+	{ 0xc,	0x6,	0x2a },
+	{ 0x26,	0x3,	0x32 },
+	{ 0x5,	0x2f,	0x33 },
+	{ 0x3c,	0x35,	0x2f },
+	{ 0x2d,	0x26,	0x3e },
+	{ 0xd,	0xa,	0x10 },
+	{ 0x25,	0x3c,	0x11 },
+	{ 0xd,	0x4,	0x2e },
+	{ 0x5,	0x19,	0x3e },
+	{ 0xc,	0x13,	0x34 },
+	{ 0x2b,	0x6,	0x24 },
+	{ 0x4,	0x3,	0xd },
+	{ 0x2f,	0x3c,	0xc },
+	{ 0x2a,	0x37,	0x1f },
+	{ 0xf,	0x12,	0x38 },
+	{ 0x38,	0xe,	0x2a },
+	{ 0x12,	0x2f,	0x19 },
+	{ 0x29,	0x2e,	0x31 },
+	{ 0x25,	0x13,	0x3e },
+	{ 0x33,	0x3e,	0x33 },
+	{ 0x1d,	0x2c,	0x25 },
+	{ 0x15,	0x15,	0x5 },
+	{ 0x32,	0x25,	0x39 },
+	{ 0x1a,	0x7,	0x1f },
+	{ 0x13,	0xe,	0x1d },
+	{ 0x36,	0x17,	0x34 },
+	{ 0xf,	0x15,	0x23 },
+	{ 0x2,	0x35,	0xd },
+	{ 0x15,	0x3f,	0xc },
+	{ 0x14,	0x2f,	0xf },
+	{ 0x19,	0x21,	0x3e },
+	{ 0x27,	0x11,	0x2f },
+	{ 0x38,	0x3f,	0x3c },
+	{ 0x36,	0x2d,	0x15 },
+	{ 0x16,	0x17,	0x2 },
+	{ 0x1,	0xa,	0x3d },
+	{ 0x1b,	0x11,	0x3f },
+	{ 0x21,	0x3c,	0xd },
+	{ 0x1a,	0x39,	0x3d },
+	{ 0x8,	0xe,	0xe },
+	{ 0x22,	0x21,	0x23 },
+	{ 0x1e,	0x30,	0x5 },
+	{ 0x1f,	0x22,	0x3d },
+	{ 0x1e,	0x2f,	0xa },
+	{ 0x0,	0x1c,	0xe },
+	{ 0x0,	0x1c,	0x15 },
+	{ 0x0,	0x1c,	0x1c },
+	{ 0x0,	0x15,	0x1c },
+	{ 0x0,	0xe,	0x1c },
+	{ 0x0,	0x7,	0x1c },
+	{ 0xe,	0xe,	0x1c },
+	{ 0x11,	0xe,	0x1c },
+	{ 0x15,	0xe,	0x1c },
+	{ 0x18,	0xe,	0x1c },
+	{ 0x1c,	0xe,	0x1c },
+	{ 0x1c,	0xe,	0x18 },
+	{ 0x1c,	0xe,	0x15 },
+	{ 0x1c,	0xe,	0x11 },
+	{ 0x1c,	0xe,	0xe },
+	{ 0x1c,	0x11,	0xe },
+	{ 0x1c,	0x15,	0xe },
+	{ 0x1c,	0x18,	0xe },
+	{ 0x1c,	0x1c,	0xe },
+	{ 0x18,	0x1c,	0xe },
+	{ 0x15,	0x1c,	0xe },
+	{ 0x11,	0x1c,	0xe },
+	{ 0xe,	0x1c,	0xe },
+	{ 0xe,	0x1c,	0x11 },
+	{ 0xe,	0x1c,	0x15 },
+	{ 0xe,	0x1c,	0x18 },
+	{ 0xe,	0x1c,	0x1c },
+	{ 0xe,	0x18,	0x1c },
+	{ 0xe,	0x15,	0x1c },
+	{ 0xe,	0x11,	0x1c },
+	{ 0x14,	0x14,	0x1c },
+	{ 0x16,	0x14,	0x1c },
+	{ 0x18,	0x14,	0x1c },
+	{ 0x1a,	0x14,	0x1c },
+	{ 0x1c,	0x14,	0x1c },
+	{ 0x1c,	0x14,	0x1a },
+	{ 0x1c,	0x14,	0x18 },
+	{ 0x1c,	0x14,	0x16 },
+	{ 0x1c,	0x14,	0x14 },
+	{ 0x1c,	0x16,	0x14 },
+	{ 0x1c,	0x18,	0x14 },
+	{ 0x1c,	0x1a,	0x14 },
+	{ 0x1c,	0x1c,	0x14 },
+	{ 0x1a,	0x1c,	0x14 },
+	{ 0x18,	0x1c,	0x14 },
+	{ 0x16,	0x1c,	0x14 },
+	{ 0x14,	0x1c,	0x14 },
+	{ 0x14,	0x1c,	0x16 },
+	{ 0x14,	0x1c,	0x18 },
+	{ 0x14,	0x1c,	0x1a },
+	{ 0x14,	0x1c,	0x1c },
+	{ 0x14,	0x1a,	0x1c },
+	{ 0x14,	0x18,	0x1c },
+	{ 0x14,	0x16,	0x1c },
+	{ 0x0,	0x0,	0x10 },
+	{ 0x4,	0x0,	0x10 },
+	{ 0x8,	0x0,	0x10 },
+	{ 0xc,	0x0,	0x10 },
+	{ 0x10,	0x0,	0x10 },
+	{ 0x10,	0x0,	0xc },
+	{ 0x10,	0x0,	0x8 },
+	{ 0x10,	0x0,	0x4 },
+	{ 0x10,	0x0,	0x0 },
+	{ 0x10,	0x4,	0x0 },
+	{ 0x10,	0x8,	0x0 },
+	{ 0x10,	0xc,	0x0 },
+	{ 0x10,	0x10,	0x0 },
+	{ 0xc,	0x10,	0x0 },
+	{ 0x8,	0x10,	0x0 },
+	{ 0x4,	0x10,	0x0 },
+	{ 0x0,	0x10,	0x0 },
+	{ 0x0,	0x10,	0x4 },
+	{ 0x0,	0x10,	0x8 },
+	{ 0x0,	0x10,	0xc },
+	{ 0x0,	0x10,	0x10 },
+	{ 0x0,	0xc,	0x10 },
+	{ 0x0,	0x8,	0x10 },
+	{ 0x0,	0x4,	0x10 },
+	{ 0x8,	0x8,	0x10 },
+	{ 0xa,	0x8,	0x10 },
+	{ 0xc,	0x8,	0x10 },
+	{ 0xe,	0x8,	0x10 },
+	{ 0x10,	0x8,	0x10 },
+	{ 0x10,	0x8,	0xe },
+	{ 0x10,	0x8,	0xc },
+	{ 0x10,	0x8,	0xa },
+	{ 0x10,	0x8,	0x8 },
+	{ 0x10,	0xa,	0x8 },
+	{ 0x10,	0xc,	0x8 },
+	{ 0x10,	0xe,	0x8 },
+	{ 0x10,	0x10,	0x8 },
+	{ 0xe,	0x10,	0x8 },
+	{ 0xc,	0x10,	0x8 },
+	{ 0xa,	0x10,	0x8 },
+	{ 0x8,	0x10,	0x8 },
+	{ 0x8,	0x10,	0xa },
+	{ 0x8,	0x10,	0xc },
+	{ 0x8,	0x10,	0xe },
+	{ 0x8,	0x10,	0x10 },
+	{ 0x8,	0xe,	0x10 },
+	{ 0x8,	0xc,	0x10 },
+	{ 0x8,	0xa,	0x10 },
+	{ 0xb,	0xb,	0x10 },
+	{ 0xc,	0xb,	0x10 },
+	{ 0xd,	0xb,	0x10 },
+	{ 0xf,	0xb,	0x10 },
+	{ 0x10,	0xb,	0x10 },
+	{ 0x10,	0xb,	0xf },
+	{ 0x10,	0xb,	0xd },
+	{ 0x10,	0xb,	0xc },
+	{ 0x10,	0xb,	0xb },
+	{ 0x10,	0xc,	0xb },
+	{ 0x10,	0xd,	0xb },
+	{ 0x10,	0xf,	0xb },
+	{ 0x10,	0x10,	0xb },
+	{ 0xf,	0x10,	0xb },
+	{ 0xd,	0x10,	0xb },
+	{ 0xc,	0x10,	0xb },
+	{ 0xb,	0x10,	0xb },
+	{ 0xb,	0x10,	0xc },
+	{ 0xb,	0x10,	0xd },
+	{ 0xb,	0x10,	0xf },
+	{ 0xb,	0x10,	0x10 },
+	{ 0xb,	0xf,	0x10 },
+	{ 0xb,	0xd,	0x10 },
+	{ 0xb,	0xc,	0x10 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 }
+};
+
+unsigned char AC[21] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+    0x0C, 0x00, 0x0F, 0x08, 0x00};
+
+static int scanPCI(int start_slt);
+static int PCIVendor(int);
+#ifdef DEBUG
+static void printslots(void);
+#endif
+extern void puthex(unsigned long);
+extern void puts(const char *);
+static void unlockS3(void);
+
+static inline void
+outw(int port, unsigned short val)
+{
+	outb(port, val >> 8);
+	outb(port+1, val);
+}
+
+int
+vga_init(unsigned char *ISA_mem)
+{
+	int slot;
+	struct VgaRegs *VgaTextRegs;
+
+	/* See if VGA already in TEXT mode - exit if so! */
+	outb(0x3CE, 0x06);
+	if ((inb(0x3CF) & 0x01) == 0){
+		puts("VGA already in text mode\n");
+		return 0;
+	}
+
+	/* If no VGA responding in text mode, then we have some work to do...
+	 */
+	slot = -1;
+	while((slot = scanPCI(slot)) > -1) { /* find video card in use  */
+		unlockVideo(slot);           /* enable I/O to card      */
+		VgaTextRegs = GenVgaTextRegs;
+
+		switch (PCIVendor(slot)) {
+		default:
+			break;
+		case(S3Vendor):
+			unlockS3();
+			break;
+
+		case(CirrusVendor):
+			outw(0x3C4, 0x0612);       /* unlock ext regs */
+			outw(0x3C4, 0x0700);       /* reset ext sequence mode */
+			break;
+
+		case(ParadiseVendor):                 /* IBM Portable 850 */
+			outw(0x3ce, 0x0f05);      /* unlock pardise registers */
+			outw(0x3c4, 0x0648);
+			outw(0x3d4, 0x2985);
+			outw(0x3d4, 0x34a6);
+			outb(0x3ce, 0x0b);       /* disable linear addressing */
+			outb(0x3cf, inb(0x3cf) & ~0x30);
+			outw(0x3c4, 0x1400);
+			outb(0x3ce, 0x0e);       /* disable 256 color mode */
+			outb(0x3cf, inb(0x3cf) & ~0x01);
+			outb(0xd00, 0xff);       /* enable auto-centering */
+			if (!(inb(0xd01) & 0x03)) {
+				outb(0x3d4, 0x33);
+				outb(0x3d5, inb(0x3d5) & ~0x90);
+				outb(0x3d4, 0x32);
+				outb(0x3d5, inb(0x3d5) | 0x04);
+				outw(0x3d4, 0x0250);
+				outw(0x3d4, 0x07ba);
+				outw(0x3d4, 0x0900);
+				outw(0x3d4, 0x15e7);
+				outw(0x3d4, 0x2a95);
+			}
+			outw(0x3d4, 0x34a0);
+			break;
+
+	#if 0 /* Untested - probably doesn't work */
+		case(MatroxVendor):
+		case(DiamondVendor):
+			puts("VGA Chip Vendor ID: ");
+			puthex(PCIVendor(slot));
+			puts("\n");
+			mdelay(1000);
+	#endif
+		};
+
+		outw(0x3C4, 0x0120);           /* disable video              */
+		setTextRegs(VgaTextRegs);      /* initial register setup     */
+		setTextCLUT(0);                /* load color lookup table    */
+		loadFont(ISA_mem);             /* load font                  */
+		setTextRegs(VgaTextRegs);      /* reload registers           */
+		outw(0x3C4, 0x0100);           /* re-enable video            */
+		clearVideoMemory();
+
+		if (PCIVendor(slot) == S3Vendor) {
+			outb(0x3c2, 0x63);                  /* MISC */
+		} /* endif */
+
+	#ifdef DEBUG
+		printslots();
+		mdelay(5000);
+	#endif
+
+		mdelay(1000);	/* give time for the video monitor to come up */
+        }
+	return (1);  /* 'CRT' I/O supported */
+}
+
+/*
+ * Write to VGA Attribute registers.
+ */
+void
+writeAttr(unsigned char index, unsigned char data, unsigned char videoOn)
+{
+	unsigned char v;
+	v = inb(0x3da);   /* reset attr. address toggle */
+	if (videoOn)
+		outb(0x3c0, (index & 0x1F) | 0x20);
+	else
+		outb(0x3c0, (index & 0x1F));
+	outb(0x3c0, data);
+}
+
+void
+setTextRegs(struct VgaRegs *svp)
+{
+	int i;
+
+	/*
+	 *  saved settings
+	 */
+	while( svp->io_port != ENDMK ) {
+		outb(svp->io_port,   svp->io_index);
+		outb(svp->io_port+1, svp->io_value);
+		svp++;
+	}
+
+	outb(0x3c2, 0x67);  /* MISC */
+	outb(0x3c6, 0xff);  /* MASK */
+
+	for ( i = 0; i < 0x10; i++)
+		writeAttr(i, AC[i], 0);  /* pallete */
+	writeAttr(0x10, 0x0c, 0);    /* text mode */
+	writeAttr(0x11, 0x00, 0);    /* overscan color (border) */
+	writeAttr(0x12, 0x0f, 0);    /* plane enable */
+	writeAttr(0x13, 0x08, 0);    /* pixel panning */
+	writeAttr(0x14, 0x00, 1);    /* color select; video on  */
+}
+
+void
+setTextCLUT(int shift)
+{
+	int i;
+
+	outb(0x3C6, 0xFF);
+	i = inb(0x3C7);
+	outb(0x3C8, 0);
+	i = inb(0x3C7);
+
+	for ( i = 0; i < 256; i++) {
+		outb(0x3C9, TextCLUT[i].r << shift);
+		outb(0x3C9, TextCLUT[i].g << shift);
+		outb(0x3C9, TextCLUT[i].b << shift);
+	}
+}
+
+void
+loadFont(unsigned char *ISA_mem)
+{
+	int i, j;
+	unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+
+	outb(0x3C2, 0x67);
+	/*
+	 * Load font
+	 */
+	i = inb(0x3DA);  /* Reset Attr toggle */
+
+	outb(0x3C0,0x30);
+	outb(0x3C0, 0x01);      /* graphics mode */
+
+	outw(0x3C4, 0x0001);    /* reset sequencer */
+	outw(0x3C4, 0x0204);    /* write to plane 2 */
+	outw(0x3C4, 0x0406);    /* enable plane graphics */
+	outw(0x3C4, 0x0003);    /* reset sequencer */
+	outw(0x3CE, 0x0402);    /* read plane 2 */
+	outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
+	outw(0x3CE, 0x0605);    /* set graphics mode */
+
+	for (i = 0;  i < sizeof(font);  i += 16) {
+		for (j = 0;  j < 16;  j++) {
+			__asm__ volatile("eieio");
+			font_page[(2*i)+j] = font[i+j];
+		}
+	}
+}
+
+static void
+unlockS3(void)
+{
+        int s3_device_id;
+	outw(0x3d4, 0x3848);
+	outw(0x3d4, 0x39a5);
+	outb(0x3d4, 0x2d);
+	s3_device_id = inb(0x3d5) << 8;
+	outb(0x3d4, 0x2e);
+	s3_device_id |= inb(0x3d5);
+
+	if (s3_device_id != 0x8812) {
+		/* From the S3 manual */
+		outb(0x46E8, 0x10);  /* Put into setup mode */
+		outb(0x3C3, 0x10);
+		outb(0x102, 0x01);   /* Enable registers */
+		outb(0x46E8, 0x08);  /* Enable video */
+		outb(0x3C3, 0x08);
+		outb(0x4AE8, 0x00);
+
+#if 0
+		outb(0x42E8, 0x80);  /* Reset graphics engine? */
+#endif
+
+		outb(0x3D4, 0x38);  /* Unlock all registers */
+		outb(0x3D5, 0x48);
+		outb(0x3D4, 0x39);
+		outb(0x3D5, 0xA5);
+		outb(0x3D4, 0x40);
+		outb(0x3D5, inb(0x3D5)|0x01);
+		outb(0x3D4, 0x33);
+		outb(0x3D5, inb(0x3D5)&~0x52);
+		outb(0x3D4, 0x35);
+		outb(0x3D5, inb(0x3D5)&~0x30);
+		outb(0x3D4, 0x3A);
+		outb(0x3D5, 0x00);
+		outb(0x3D4, 0x53);
+		outb(0x3D5, 0x00);
+		outb(0x3D4, 0x31);
+		outb(0x3D5, inb(0x3D5)&~0x4B);
+		outb(0x3D4, 0x58);
+
+		outb(0x3D5, 0);
+
+		outb(0x3D4, 0x54);
+		outb(0x3D5, 0x38);
+		outb(0x3D4, 0x60);
+		outb(0x3D5, 0x07);
+		outb(0x3D4, 0x61);
+		outb(0x3D5, 0x80);
+		outb(0x3D4, 0x62);
+		outb(0x3D5, 0xA1);
+		outb(0x3D4, 0x69);  /* High order bits for cursor address */
+		outb(0x3D5, 0);
+
+		outb(0x3D4, 0x32);
+		outb(0x3D5, inb(0x3D5)&~0x10);
+	} else {
+                outw(0x3c4, 0x0806);            /* IBM Portable 860 */
+                outw(0x3c4, 0x1041);
+                outw(0x3c4, 0x1128);
+                outw(0x3d4, 0x4000);
+                outw(0x3d4, 0x3100);
+                outw(0x3d4, 0x3a05);
+                outw(0x3d4, 0x6688);
+                outw(0x3d4, 0x5800);            /* disable linear addressing */
+                outw(0x3d4, 0x4500);            /* disable H/W cursor */
+                outw(0x3c4, 0x5410);            /* enable auto-centering */
+                outw(0x3c4, 0x561f);
+                outw(0x3c4, 0x1b80);            /* lock DCLK selection */
+                outw(0x3d4, 0x3900);            /* lock S3 registers */
+                outw(0x3d4, 0x3800);
+	} /* endif */
+}
+
+/*
+ * cursor() sets an offset (0-1999) into the 80x25 text area.
+ */
+void
+cursor(int x, int y)
+{
+	int pos = (y*cols)+x;
+	outb(0x3D4, 14);
+	outb(0x3D5, pos >> 8);
+	outb(0x3D4, 15);
+	outb(0x3D5, pos);
+}
+
+void
+clearVideoMemory(void)
+{
+	int i, j;
+	for (i = 0;  i < lines;  i++) {
+		for (j = 0;  j < cols;  j++) {
+			vidmem[((i*cols)+j)*2] = 0x20;	/* fill with space character */
+			vidmem[((i*cols)+j)*2+1] = 0x07;  /* set bg & fg attributes */
+		}
+	}
+}
+
+/* ============ */
+
+
+#define NSLOTS 8
+#define NPCIREGS  5
+
+
+/*
+ should use devfunc number/indirect method to be totally safe on
+ all machines, this works for now on 3 slot Moto boxes
+*/
+
+struct PCI_ConfigInfo {
+  unsigned long * config_addr;
+  unsigned long regs[NPCIREGS];
+} PCI_slots [NSLOTS] = {
+
+    { (unsigned long *)0x80808000, {0xDEADBEEF,} },   /* onboard */
+    { (unsigned long *)0x80800800, {0xDEADBEEF,} },   /* onboard */
+    { (unsigned long *)0x80801000, {0xDEADBEEF,} },   /* onboard */
+    { (unsigned long *)0x80802000, {0xDEADBEEF,} },   /* onboard */
+    { (unsigned long *)0x80804000, {0xDEADBEEF,} },   /* onboard */
+    { (unsigned long *)0x80810000, {0xDEADBEEF,} },   /* slot A/1 */
+    { (unsigned long *)0x80820000, {0xDEADBEEF,} },   /* slot B/2 */
+    { (unsigned long *)0x80840000, {0xDEADBEEF,} }    /* slot C/3 */
+};
+
+
+
+/*
+ * The following code modifies the PCI Command register
+ * to enable memory and I/O accesses.
+ */
+void
+unlockVideo(int slot)
+{
+       volatile unsigned char * ppci;
+
+        ppci =  (unsigned char * )PCI_slots[slot].config_addr;
+	ppci[4] = 0x0003;         /* enable memory and I/O accesses */
+	ppci[0x10] = 0x00000;     /* turn off memory mapping */
+	ppci[0x11] = 0x00000;     /* mem_base = 0 */
+	ppci[0x12] = 0x00000;
+	ppci[0x13] = 0x00000;
+	__asm__ volatile("eieio");
+
+	outb(0x3d4, 0x11);
+	outb(0x3d5, 0x0e);   /* unlock CR0-CR7 */
+}
+
+long
+SwapBytes(long lv)   /* turn little endian into big indian long */
+{
+    long t;
+    t  = (lv&0x000000FF) << 24;
+    t |= (lv&0x0000FF00) << 8;
+    t |= (lv&0x00FF0000) >> 8;
+    t |= (lv&0xFF000000) >> 24;
+    return(t);
+}
+
+
+#define DEVID   0
+#define CMD     1
+#define CLASS   2
+#define MEMBASE 4
+
+int
+scanPCI(int start_slt)
+{
+	int slt, r;
+	struct PCI_ConfigInfo *pslot;
+	int theSlot = -1;
+	int highVgaSlot = 0;
+
+	for ( slt = start_slt + 1; slt < NSLOTS; slt++) {
+		pslot = &PCI_slots[slt];
+		for ( r = 0; r < NPCIREGS; r++) {
+			pslot->regs[r] = SwapBytes ( pslot->config_addr[r] );
+		}
+		/* card in slot ? */
+		if ( pslot->regs[DEVID] != 0xFFFFFFFF ) {
+			/* VGA ? */
+			if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) ||
+			     ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) {
+				highVgaSlot = slt;
+				/* did firmware enable it ? */
+				if ( (pslot->regs[CMD] & 0x03) ) {
+					theSlot = slt;
+					break;
+				}
+			}
+		}
+	}
+
+	return ( theSlot );
+}
+
+/* return Vendor ID of card in the slot */
+static
+int PCIVendor(int slotnum) {
+ struct PCI_ConfigInfo *pslot;
+
+ pslot = &PCI_slots[slotnum];
+
+return (pslot->regs[DEVID] & 0xFFFF);
+}
+
+#ifdef DEBUG
+static
+void printslots(void)
+{
+	int i;
+#if 0
+	struct PCI_ConfigInfo *pslot;
+#endif
+	for(i=0; i < NSLOTS; i++) {
+#if 0
+		pslot = &PCI_slots[i];
+		printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n",
+		       i, pslot->config_addr, pslot->regs[0], pslot->regs[2]);
+#else
+		puts("PCI Slot number: "); puthex(i);
+		puts(" Vendor ID: ");
+		puthex(PCIVendor(i)); puts("\n");
+#endif
+	}
+}
+#endif /* DEBUG */
diff -Nru a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile
--- a/arch/ppc/boot/openfirmware/Makefile	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc/boot/openfirmware/Makefile	Sat Apr  3 19:38:42 2004
@@ -104,10 +104,10 @@
 			$(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 @@
 			$(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 $@
@@ -162,7 +162,7 @@
 		 $(images)/miboot.initrd.image
 	@echo '  kernel: $@ is ready ($<)'
 
-TFTPIMAGE	:= /tftpboot/zImage.
+TFTPIMAGE	:= /tftpboot/zImage
 
 .PHONY: znetboot znetboot.initrd
 znetboot:	$(images)/vmlinux.coff		\
diff -Nru a/arch/ppc/boot/prep/Makefile b/arch/ppc/boot/prep/Makefile
--- a/arch/ppc/boot/prep/Makefile	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,109 +0,0 @@
-# arch/ppc/boot/Makefile
-#
-# 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.
-#
-# Tom Rini	January 2001
-#
-# Originally:
-# arch/ppc/boot/Makefile
-# Copyright (C) 1994 by Linus Torvalds
-# Adapted for PowerPC by Gary Thomas
-# modified by Cort (cort@cs.nmt.edu)
-#
-
-TFTPIMAGE		:= /tftpboot/zImage.prep
-ifeq ($(CONFIG_SMP),y)
-TFTPIMAGE		:= $(TFTPIMAGE).smp
-endif
-
-boot-y				:= head.o misc.o
-boot-$(CONFIG_VGA_CONSOLE)	+= vreset.o kbd.o
-
-boot	:= arch/ppc/boot
-common	:= $(boot)/common
-utils	:= $(boot)/utils
-bootlib	:= $(boot)/lib
-images	:= $(boot)/images
-simple	:= $(boot)/simple
-of1275	:= $(boot)/of1275
-
-OBJCOPYFLAGS	:= -O elf32-powerpc
-LIBS 		:= $(common)/lib.a $(bootlib)/lib.a $(of1275)/lib.a
-
-targets		:= $(boot-y) dummy.o ../simple/legacy.o
-OBJS		:= $(addprefix $(obj)/,$(boot-y)) $(simple)/legacy.o
-
-# Extra include search dirs
-CFLAGS_kbd.o			+= -Idrivers/char
-
-zImage: initrd :=
-zImage: $(images)/zImage.prep
-	@echo '  kernel: $@ is ready ($<)'
-
-zImage.initrd: initrd := .initrd
-zImage.initrd: $(images)/zImage.initrd.prep
-	@echo '  kernel: $@ is ready ($<)'
-
-$(images)/ramdisk.image.gz:
-	@echo '  MISSING $@'
-	@echo '          RAM disk image must be provided separately'
-	@/bin/false
-
-OBJCOPYFLAGS_image.o   := \
-	--add-section=.image=$(images)/vmlinux.gz \
-	--set-section-flags=.image=contents,alloc,load,readonly,data
-targets	+= image.o
-$(obj)/image.o: $(obj)/dummy.o $(images)/vmlinux.gz
-	$(call if_changed,objcopy)
-
-OBJCOPYFLAGS_image.initrd.o    := \
-	--add-section=.ramdisk=$(images)/ramdisk.image.gz \
-	--set-section-flags=.ramdisk=contents,alloc,load,readonly,data \
-	--add-section=.image=$(images)/vmlinux.gz \
-	--set-section-flags=.image=contents,alloc,load,readonly,data
-targets	+= image.initrd.o
-$(obj)/image.initrd.o: $(obj)/dummy.o $(images)/vmlinux.gz $(images)/ramdisk.image.gz
-	$(call if_changed,objcopy)
-
-LDFLAGS_zImage.bin		:= -Ttext 0x00800000 -Bstatic -T
-LDFLAGS_zImage.initrd.bin	:= -Ttext 0x00800000 -Bstatic -T
-targets += zImage.bin
-$(obj)/zImage.bin: $(boot)/ld.script $(OBJS) $(obj)/image.o $(LIBS)
-	$(call if_changed,ld)
-targets += zImage.initrd.bin
-$(obj)/zImage.initrd.bin: $(boot)/ld.script $(OBJS) $(obj)/image.initrd.o $(LIBS)
-	$(call if_changed,ld)
-
-OBJCOPYFLAGS_zImage		:= -R .comment -R .stab -R .stabstr
-OBJCOPYFLAGS_zImage.initrd	:= -R .comment -R .stab -R .stabstr
-targets += zImage
-$(obj)/zImage: %: %.bin FORCE
-	$(call if_changed,objcopy)
-targets += zImage.initrd
-$(obj)/zImage.initrd: %: %.bin FORCE
-	$(call if_changed,objcopy)
-
-quiet_cmd_mkprep = MKPREP  $@
-      cmd_mkprep = $(utils)/mkprep -pbp $< $@
-
-$(images)/zImage.prep: $(obj)/zImage $(utils)/mkprep
-	$(call cmd,mkprep)
-$(images)/zImage.initrd.prep: $(obj)/zImage.initrd $(utils)/mkprep
-	$(call cmd,mkprep)
-
-#
-# Convinient shorthands for various targets
-#
-floppy: zImage
-	dd if=$(images)/zImage.prep of=/dev/fd0H1440 bs=64b
-
-znetboot : zImage
-	cp $(images)/zImage.prep $(TFTPIMAGE)
-	@echo '  kernel: $@ is ready ($<)'
-
-znetboot.initrd : zImage.initrd
-	cp $(images)/zImage.initrd.prep $(TFTPIMAGE)
-	@echo '  kernel: $@ is ready ($<)'
-
diff -Nru a/arch/ppc/boot/prep/dummy.c b/arch/ppc/boot/prep/dummy.c
--- a/arch/ppc/boot/prep/dummy.c	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,4 +0,0 @@
-int main(void)
-{
-	return 0;
-}
diff -Nru a/arch/ppc/boot/prep/head.S b/arch/ppc/boot/prep/head.S
--- a/arch/ppc/boot/prep/head.S	Sat Apr  3 19:38:41 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,192 +0,0 @@
-#include <asm/ppc_asm.h>
-#include <asm/reg.h>
-#include <asm/cache.h>
-
-	.text
-
-/*
- * Boot loader philosophy:
- *      ROM loads us to some arbitrary location
- *      Move the boot code to the link address (8M)
- *      Call decompress_kernel()
- *         Relocate the initrd, zimage and residual data to 8M
- *         Decompress the kernel to 0
- *      Jump to the kernel entry
- *            -- Cort
- */
-	.globl	start
-start:
-	bl	start_
-start_:
-
-        /* Enable, invalidate, Disable L1 icache/dcache */
-	li	r8, 0
-	ori	r8, r8, (HID0_ICE|HID0_DCE|HID0_ICFI|HID0_DCI)
-	mfspr	r11,HID0
-	or	r11,r11,r8
-	andc	r10,r11,r8
-	isync
-	mtspr	HID0,r8
-	sync
-	isync
-	mtspr	HID0,r10
-	sync
-	isync
-
-	mr	r11,r3		/* Save pointer to residual/board data */
-
-/*
- * Save the OF pointer to r25, but only if the entry point is in a sane
- * location; if not we store 0.  If there is no entry point, or it is
- * invalid, we establish the default MSR value immediately.  Otherwise,
- * we defer doing that, to allow OF functions to be called, until we
- * begin uncompressing the kernel.
- */
-	lis	r3,0x0fff		/* r3 = 0x0fffffff */
-	ori	r3,r3,0xffff
-
-	subc	r3,r3,r5		/* r3 = (r5 <= r3) ? ~0 : 0 */
-	subfe	r3,r3,r3
-	nand	r3,r3,r3
-
-	and.	r5,r5,r3		/* r5 will be cleared if (r5 > r3) */
-	bne+	haveOF
-
-	li	r3,MSR_IP|MSR_FP	/* Not OF: set MSR immediately */
-  	mtmsr	r3
-	isync
-haveOF:
-	mr	r25,r5
-
-	/* compute the size of the whole image in words. */
-	lis	r4,start@h
-	ori	r4,r4,start@l
-	lis	r5,end@h
-	ori	r5,r5,end@l
-	addi	r5,r5,3		/* round up */
-	sub	r5,r5,r4	/* end - start */
-	srwi	r5,r5,2
-	mr	r7,r5		/* Save for later use. */
-
-	/* check if we need to relocate ourselves to the link addr or were
-	 * we loaded there to begin with -- Cort */
-	mflr	r3
-	subi	r3,r3,4		/* we get the nip, not the ip of the branch */
-	mr	r8,r3
-	cmp	0,r3,r4
-	beq	start_ldr	/* If 0, we don't need to relocate */
-/*
- * no matter where we're loaded, move ourselves to -Ttext address
- */
-relocate:
-	mflr	r3		/* Compute code bias */
-	subi	r3,r3,4
-	mr	r8,r3
-	lis	r4,start@h
-	ori	r4,r4,start@l
-	mr	r5,r7		/* Get the # of longwords again */
-	mtctr	r5		/* Setup for loop */
-	li	r6,0
-	subi	r3,r3,4
-	subi	r4,r4,4
-00:	lwzu	r5,4(r3)
-	stwu	r5,4(r4)
-	xor	r6,r6,r5
-	bdnz	00b
-  	lis	r3,start_ldr@h
-	ori	r3,r3,start_ldr@l
-	mtlr	r3		/* Easiest way to do an absolute jump */
-	blr
-
-start_ldr:
-/* Some boards don't boot up with the I-cache enabled.  Do that
- * now because the decompress runs much faster that way.
- * As a side effect, we have to ensure the data cache is not enabled
- * so we can access the serial I/O without trouble.
- */
-	bl	flush_instruction_cache
-
-/* Clear all of BSS */
-	lis	r3,edata@h
-	ori	r3,r3,edata@l
-	lis	r4,end@h
-	ori	r4,r4,end@l
-	subi	r3,r3,4
-	subi	r4,r4,4
-	li	r0,0
-50:	stwu	r0,4(r3)
-	cmp	0,r3,r4
-	bne	50b
-90:	mr	r9,r1			/* Save old stack pointer (in case it matters) */
-	lis	r1,.stack@h
-	ori	r1,r1,.stack@l
-	addi	r1,r1,4096*2
-	subi	r1,r1,256
-	li	r2,0x000F		/* Mask pointer to 16-byte boundary */
-	andc	r1,r1,r2
-
-/* Run loader */
-	mr	r3,r8			/* Load point */
-	mr	r4,r7			/* Program length */
-	mr	r5,r6			/* Checksum */
-	mr	r6,r11			/* Residual data */
-	mr      r7,r25                  /* Validated OFW interface */
-	bl	decompress_kernel
-
-	/*
-	 * We have to do this after decompress_kernel, just to make
-	 * sure we don't wipe out things mapped in BATs which we need.
-	 * -- Tom
-	 */
-	li      r6,0
-	/* Test for a 601 */
-	mfspr	r9,PVR
-	srwi	r9,r9,16
-	cmpi	0,r9,1          /* 601 ? */
-	beq	.clearbats_601
-
-	/* Clear BATS */
-	mtspr   DBAT0U,r6
-	mtspr	DBAT0L,r6
-	mtspr   DBAT1U,r6
-	mtspr	DBAT1L,r6
-	mtspr   DBAT2U,r6
-	mtspr	DBAT2L,r6
-	mtspr   DBAT3U,r6
-	mtspr	DBAT3L,r6
-.clearbats_601:
-	mtspr   IBAT0U,r6
-	mtspr	IBAT0L,r6
-	mtspr   IBAT1U,r6
-	mtspr	IBAT1L,r6
-	mtspr	IBAT2U,r6
-	mtspr   IBAT2L,r6
-	mtspr   IBAT3U,r6
-	mtspr	IBAT3L,r6
-	isync
-	sync
-	sync
-
-	/* Set segment registers */
-	li	r6,16		/* load up segment register values */
-	mtctr	r6		/* for context 0 */
-	lis	r6,0x2000	/* Ku = 1, VSID = 0 */
-	li	r10,0
-3:	mtsrin	r6,r10
-	addi	r6,r6,0x111	/* increment VSID */
-	addis	r10,r10,0x1000	/* address of next segment */
-	bdnz	3b
-
-	/* tell kernel we're prep, by putting 0xdeadc0de at KERNELLOAD,
-	 * and tell the kernel to start on the 4th instruction since we
-	 * overwrite the first 3 sometimes (which are 'nop').
-	 */
-	li	r9,0xc
-	mtlr	r9
-	lis	r10,0xdeadc0de@h
-	ori	r10,r10,0xdeadc0de@l
-	li	r9,0
-	stw	r10,0(r9)
-	blr
-
-	.comm	.stack,4096*2,4
diff -Nru a/arch/ppc/boot/prep/iso_font.h b/arch/ppc/boot/prep/iso_font.h
--- a/arch/ppc/boot/prep/iso_font.h	Sat Apr  3 19:38:56 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,257 +0,0 @@
-static const unsigned char font[] = {
-/* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
-/* 0x02 */ 0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00,
-/* 0x03 */ 0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,
-/* 0x04 */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
-/* 0x05 */ 0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x06 */ 0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x07 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x08 */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-/* 0x09 */ 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,
-/* 0x0A */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF,
-/* 0x0B */ 0x00,0x00,0x3E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
-/* 0x0C */ 0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x0D */ 0x00,0x00,0x30,0x38,0x3C,0x36,0x33,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,
-/* 0x0E */ 0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00,
-/* 0x0F */ 0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x10 */ 0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,
-/* 0x11 */ 0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
-/* 0x12 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,
-/* 0x13 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
-/* 0x14 */ 0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,
-/* 0x15 */ 0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,
-/* 0x16 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,
-/* 0x17 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,
-/* 0x18 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x19 */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,
-/* 0x1A */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x1B */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x1C */ 0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x1D */ 0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x1E */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,
-/* 0x1F */ 0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
-/* 0x20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x21 */ 0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x22 */ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x23 */ 0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,
-/* 0x24 */ 0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00,
-/* 0x25 */ 0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00,
-/* 0x26 */ 0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x27 */ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x28 */ 0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,
-/* 0x29 */ 0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,
-/* 0x2A */ 0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x2B */ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x2C */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
-/* 0x2D */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x2E */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x2F */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,
-/* 0x30 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
-/* 0x31 */ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,
-/* 0x32 */ 0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00,
-/* 0x33 */ 0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x34 */ 0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,
-/* 0x35 */ 0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x36 */ 0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x37 */ 0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
-/* 0x38 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x39 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00,
-/* 0x3A */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
-/* 0x3B */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
-/* 0x3C */ 0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,
-/* 0x3D */ 0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x3E */ 0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
-/* 0x3F */ 0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x40 */ 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00,
-/* 0x41 */ 0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0x42 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,
-/* 0x43 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00,
-/* 0x44 */ 0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00,
-/* 0x45 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
-/* 0x46 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
-/* 0x47 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00,
-/* 0x48 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0x49 */ 0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x4A */ 0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
-/* 0x4B */ 0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
-/* 0x4C */ 0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
-/* 0x4D */ 0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0x4E */ 0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0x4F */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x50 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
-/* 0x51 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00,
-/* 0x52 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
-/* 0x53 */ 0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x54 */ 0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x55 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x56 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00,
-/* 0x57 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00,
-/* 0x58 */ 0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0x59 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x5A */ 0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00,
-/* 0x5B */ 0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,
-/* 0x5C */ 0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
-/* 0x5D */ 0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,
-/* 0x5E */ 0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x5F */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,
-/* 0x60 */ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x61 */ 0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x62 */ 0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,
-/* 0x63 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x64 */ 0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x65 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x66 */ 0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
-/* 0x67 */ 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,
-/* 0x68 */ 0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
-/* 0x69 */ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x6A */ 0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,
-/* 0x6B */ 0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00,
-/* 0x6C */ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x6D */ 0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xD6,0xD6,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0x6E */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
-/* 0x6F */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x70 */ 0x00,0x00,0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,
-/* 0x71 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00,
-/* 0x72 */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
-/* 0x73 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x74 */ 0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,
-/* 0x75 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x76 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,
-/* 0x77 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00,
-/* 0x78 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,
-/* 0x79 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00,
-/* 0x7A */ 0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
-/* 0x7B */ 0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,
-/* 0x7C */ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x7D */ 0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
-/* 0x7E */ 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0x7F */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,
-/* 0x80 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00,
-/* 0x81 */ 0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x82 */ 0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x83 */ 0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x84 */ 0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x85 */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x86 */ 0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x87 */ 0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00,
-/* 0x88 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x89 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x8A */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x8B */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x8C */ 0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x8D */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0x8E */ 0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0x8F */ 0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0x90 */ 0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00,
-/* 0x91 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00,
-/* 0x92 */ 0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00,
-/* 0x93 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x94 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x95 */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x96 */ 0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x97 */ 0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0x98 */ 0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
-/* 0x99 */ 0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x9A */ 0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0x9B */ 0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x9C */ 0x00,0x38,0x6C,0x64,0x60,0xF8,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00,
-/* 0x9D */ 0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0x9E */ 0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00,
-/* 0x9F */ 0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00,
-/* 0xA0 */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0xA1 */ 0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
-/* 0xA2 */ 0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0xA3 */ 0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
-/* 0xA4 */ 0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
-/* 0xA5 */ 0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0xA6 */ 0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xA7 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xA8 */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
-/* 0xA9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,
-/* 0xAA */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
-/* 0xAB */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00,
-/* 0xAC */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00,
-/* 0xAD */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,
-/* 0xAE */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xAF */ 0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xB0 */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
-/* 0xB1 */ 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
-/* 0xB2 */ 0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,
-/* 0xB3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xB4 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xB5 */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xB6 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xB7 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xB8 */ 0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xB9 */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xBA */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xBB */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xBC */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xBD */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xBE */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xBF */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xC0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xC1 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xC2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xC3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xC4 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xC5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xC6 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xC7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xC8 */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xC9 */ 0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xCA */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xCB */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xCC */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xCD */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xCE */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xCF */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xD0 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xD1 */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xD2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xD3 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xD4 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xD5 */ 0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xD6 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xD7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
-/* 0xD8 */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xD9 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xDA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xDB */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-/* 0xDC */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
-/* 0xDD */ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
-/* 0xDE */ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
-/* 0xDF */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xE0 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00,
-/* 0xE1 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xFC,0xC6,0xC6,0xC6,0xC6,0xDC,0xC0,0xC0,0x00,0x00,
-/* 0xE2 */ 0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,
-/* 0xE3 */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,
-/* 0xE4 */ 0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
-/* 0xE5 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
-/* 0xE6 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0xC0,0x00,0x00,0x00,
-/* 0xE7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
-/* 0xE8 */ 0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,
-/* 0xE9 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
-/* 0xEA */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00,
-/* 0xEB */ 0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,
-/* 0xEC */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xED */ 0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00,
-/* 0xEE */ 0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00,
-/* 0xEF */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
-/* 0xF0 */ 0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,
-/* 0xF1 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,
-/* 0xF2 */ 0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00,
-/* 0xF3 */ 0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00,
-/* 0xF4 */ 0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
-/* 0xF5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
-/* 0xF6 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
-/* 0xF7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xF8 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xF9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xFA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xFB */ 0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00,
-/* 0xFC */ 0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xFD */ 0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-/* 0xFE */ 0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,
-};
diff -Nru a/arch/ppc/boot/prep/kbd.c b/arch/ppc/boot/prep/kbd.c
--- a/arch/ppc/boot/prep/kbd.c	Sat Apr  3 19:38:41 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,248 +0,0 @@
-#include <linux/keyboard.h>
-
-#include "defkeymap.c"	/* yeah I know it's bad -- Cort */
-
-
-unsigned char shfts, ctls, alts, caps;
-
-#define	KBDATAP		0x60	/* kbd data port */
-#define	KBSTATUSPORT	0x61	/* kbd status */
-#define	KBSTATP		0x64	/* kbd status port */
-#define	KBINRDY		0x01
-#define	KBOUTRDY	0x02
-
-extern unsigned char inb(int port);
-extern void outb(int port, char val);
-extern void puts(const char *);
-extern void puthex(unsigned long val);
-extern void udelay(long x);
-
-static int kbd(int noblock)
-{
-	unsigned char dt, brk, val;
-	unsigned code;
-loop:
-	if (noblock) {
-	    if ((inb(KBSTATP) & KBINRDY) == 0)
-		return (-1);
-	} else while((inb(KBSTATP) & KBINRDY) == 0) ;
-
-	dt = inb(KBDATAP);
-
-	brk = dt & 0x80;	/* brk == 1 on key release */
-	dt = dt & 0x7f;		/* keycode */
-
-	if (shfts)
-	    code = shift_map[dt];
-	else if (ctls)
-	    code = ctrl_map[dt];
-	else
-	    code = plain_map[dt];
-
-	val = KVAL(code);
-	switch (KTYP(code) & 0x0f) {
-	    case KT_LATIN:
-		if (brk)
-		    break;
-		if (alts)
-		    val |= 0x80;
-		if (val == 0x7f)	/* map delete to backspace */
-		    val = '\b';
-		return val;
-
-	    case KT_LETTER:
-		if (brk)
-		    break;
-		if (caps)
-		    val -= 'a'-'A';
-		return val;
-
-	    case KT_SPEC:
-		if (brk)
-		    break;
-		if (val == KVAL(K_CAPS))
-		    caps = !caps;
-		else if (val == KVAL(K_ENTER)) {
-enter:		    /* Wait for key up */
-		    while (1) {
-			while((inb(KBSTATP) & KBINRDY) == 0) ;
-			dt = inb(KBDATAP);
-			if (dt & 0x80) /* key up */ break;
-		    }
-		    return 10;
-		}
-		break;
-
-	    case KT_PAD:
-		if (brk)
-		    break;
-		if (val < 10)
-		    return val;
-		if (val == KVAL(K_PENTER))
-		    goto enter;
-		break;
-
-	    case KT_SHIFT:
-		switch (val) {
-		    case KG_SHIFT:
-		    case KG_SHIFTL:
-		    case KG_SHIFTR:
-			shfts = brk ? 0 : 1;
-			break;
-		    case KG_ALT:
-		    case KG_ALTGR:
-			alts = brk ? 0 : 1;
-			break;
-		    case KG_CTRL:
-		    case KG_CTRLL:
-		    case KG_CTRLR:
-			ctls = brk ? 0 : 1;
-			break;
-		}
-		break;
-
-	    case KT_LOCK:
-		switch (val) {
-		    case KG_SHIFT:
-		    case KG_SHIFTL:
-		    case KG_SHIFTR:
-			if (brk)
-			    shfts = !shfts;
-			break;
-		    case KG_ALT:
-		    case KG_ALTGR:
-			if (brk)
-			    alts = !alts;
-			break;
-		    case KG_CTRL:
-		    case KG_CTRLL:
-		    case KG_CTRLR:
-			if (brk)
-			    ctls = !ctls;
-			break;
-		}
-		break;
-	}
-	if (brk) return (-1);  /* Ignore initial 'key up' codes */
-	goto loop;
-}
-
-static int __kbdreset(void)
-{
-	unsigned char c;
-	int i, t;
-
-	/* flush input queue */
-	t = 2000;
-	while ((inb(KBSTATP) & KBINRDY))
-	{
-		(void)inb(KBDATAP);
-		if (--t == 0)
-			return 1;
-	}
-	/* Send self-test */
-	t = 20000;
-	while (inb(KBSTATP) & KBOUTRDY)
-		if (--t == 0)
-			return 2;
-	outb(KBSTATP,0xAA);
-	t = 200000;
-	while ((inb(KBSTATP) & KBINRDY) == 0)	/* wait input ready */
-		if (--t == 0)
-			return 3;
-	if ((c = inb(KBDATAP)) != 0x55)
-	{
-		puts("Keyboard self test failed - result:");
-		puthex(c);
-		puts("\n");
-	}
-	/* Enable interrupts and keyboard controller */
-	t = 20000;
-	while (inb(KBSTATP) & KBOUTRDY)
-		if (--t == 0) return 4;
-	outb(KBSTATP,0x60);
-	t = 20000;
-	while (inb(KBSTATP) & KBOUTRDY)
-		if (--t == 0) return 5;
-	outb(KBDATAP,0x45);
-	for (i = 0;  i < 10000;  i++) udelay(1);
-
-	t = 20000;
-	while (inb(KBSTATP) & KBOUTRDY)
-		if (--t == 0) return 6;
-	outb(KBSTATP,0x20);
-	t = 200000;
-	while ((inb(KBSTATP) & KBINRDY) == 0)	/* wait input ready */
-		if (--t == 0) return 7;
-	if (! (inb(KBDATAP) & 0x40)) {
-		/*
-		 * Quote from PS/2 System Reference Manual:
-		 *
-		 * "Address hex 0060 and address hex 0064 should be
-		 * written only when the input-buffer-full bit and
-		 * output-buffer-full bit in the Controller Status
-		 * register are set 0." (KBINRDY and KBOUTRDY)
-		 */
-		t = 200000;
-		while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
-			if (--t == 0) return 8;
-		outb(KBDATAP,0xF0);
-		t = 200000;
-		while (inb(KBSTATP) & (KBINRDY | KBOUTRDY))
-			if (--t == 0) return 9;
-		outb(KBDATAP,0x01);
-	}
-	t = 20000;
-	while (inb(KBSTATP) & KBOUTRDY)
-		if (--t == 0) return 10;
-	outb(KBSTATP,0xAE);
-	return 0;
-}
-
-static void kbdreset(void)
-{
-	int ret = __kbdreset();
-
-	if (ret) {
-		puts("__kbdreset failed: ");
-		puthex(ret);
-		puts("\n");
-	}
-}
-
-/* We have to actually read the keyboard when CRT_tstc is called,
- * since the pending data might be a key release code, and therefore
- * not valid data.  In this case, kbd() will return -1, even though there's
- * data to be read.  Of course, we might actually read a valid key press,
- * in which case it gets queued into key_pending for use by CRT_getc.
- */
-
-static int kbd_reset = 0;
-
-static int key_pending = -1;
-
-int CRT_getc(void)
-{
-	int c;
-	if (!kbd_reset) {kbdreset(); kbd_reset++; }
-
-        if (key_pending != -1) {
-                c = key_pending;
-                key_pending = -1;
-                return c;
-        } else {
-	while ((c = kbd(0)) == 0) ;
-                return c;
-        }
-}
-
-int CRT_tstc(void)
-{
-	if (!kbd_reset) {kbdreset(); kbd_reset++; }
-
-        while (key_pending == -1 && ((inb(KBSTATP) & KBINRDY) != 0)) {
-                key_pending = kbd(1);
-        }
-
-        return (key_pending != -1);
-}
diff -Nru a/arch/ppc/boot/prep/misc.c b/arch/ppc/boot/prep/misc.c
--- a/arch/ppc/boot/prep/misc.c	Sat Apr  3 19:38:45 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,425 +0,0 @@
-/*
- * arch/ppc/boot/prep/misc.c
- *
- * Adapted for PowerPC by Gary Thomas
- *
- * Rewritten by Cort Dougan (cort@cs.nmt.edu)
- * One day to be replaced by a single bootloader for chrp/prep/pmac. -- Cort
- */
-
-#include <linux/types.h>
-#include <linux/string.h>
-#include <asm/residual.h>
-#include <linux/config.h>
-#include <linux/threads.h>
-#include <linux/elf.h>
-#include <linux/pci_ids.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-#include <asm/bootinfo.h>
-#include <asm/mmu.h>
-#include <asm/byteorder.h>
-#include "of1275.h"
-#include "nonstdio.h"
-#include "zlib.h"
-
-/*
- * Please send me load/board info and such data for hardware not
- * listed here so I can keep track since things are getting tricky
- * with the different load addrs with different firmware.  This will
- * help to avoid breaking the load/boot process.
- * -- Cort
- */
-char *avail_ram;
-char *end_avail;
-
-/* The linker tells us where the image is. */
-extern char __image_begin, __image_end;
-extern char __ramdisk_begin, __ramdisk_end;
-extern char _end[];
-
-#ifdef CONFIG_CMDLINE
-#define CMDLINE CONFIG_CMDLINE
-#else
-#define CMDLINE ""
-#endif
-char cmd_preset[] = CMDLINE;
-char cmd_buf[256];
-char *cmd_line = cmd_buf;
-
-int keyb_present = 1;	/* keyboard controller is present by default */
-RESIDUAL hold_resid_buf;
-RESIDUAL *hold_residual = &hold_resid_buf;
-unsigned long initrd_size = 0;
-
-char *zimage_start;
-int zimage_size;
-
-#if defined(CONFIG_SERIAL_8250_CONSOLE)
-unsigned long com_port;
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-#ifdef CONFIG_VGA_CONSOLE
-char *vidmem = (char *)0xC00B8000;
-int lines = 25, cols = 80;
-int orig_x, orig_y = 24;
-#endif /* CONFIG_VGA_CONSOLE */
-
-extern int CRT_tstc(void);
-extern int vga_init(unsigned char *ISA_mem);
-extern void gunzip(void *, int, unsigned char *, int *);
-extern unsigned long serial_init(int chan, void *ignored);
-extern void serial_fixups(void);
-extern unsigned long get_mem_size(void);
-
-void
-writel(unsigned int val, unsigned int address)
-{
-	/* Ensure I/O operations complete */
-	__asm__ volatile("eieio");
-	*(unsigned int *)address = cpu_to_le32(val);
-}
-
-unsigned int
-readl(unsigned int address)
-{
-	/* Ensure I/O operations complete */
-	__asm__ volatile("eieio");
-	return le32_to_cpu(*(unsigned int *)address);
-}
-
-#define PCI_CFG_ADDR(dev,off)	((0x80<<24) | (dev<<8) | (off&0xfc))
-#define PCI_CFG_DATA(off)	(0x80000cfc+(off&3))
-
-static void
-pci_read_config_32(unsigned char devfn,
-		unsigned char offset,
-		unsigned int *val)
-{
-	writel(PCI_CFG_ADDR(devfn,offset), 0x80000cf8);
-	*val = readl(PCI_CFG_DATA(offset));
-	return;
-}
-
-#ifdef CONFIG_VGA_CONSOLE
-void
-scroll(void)
-{
-	int i;
-
-	memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
-	for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
-		vidmem[i] = ' ';
-}
-#endif /* CONFIG_VGA_CONSOLE */
-
-unsigned long
-decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
-		  RESIDUAL *residual, void *OFW_interface)
-{
-	int timer = 0;
-	extern unsigned long start;
-	char *cp, ch;
-	unsigned long TotalMemory;
-	int start_multi = 0;
-	unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base;
-
-	/* If we have Open Firmware, initialise it immediately */
-	if (OFW_interface)
-		ofinit(OFW_interface);
-
-	serial_fixups();
-#if defined(CONFIG_SERIAL_8250_CONSOLE)
-	com_port = serial_init(0, NULL);
-#endif /* CONFIG_SERIAL_8250_CONSOLE */
-#if defined(CONFIG_VGA_CONSOLE)
-	vga_init((unsigned char *)0xC0000000);
-#endif /* CONFIG_VGA_CONSOLE */
-
-	/*
-	 * Tell the user where we were loaded at and where we were relocated
-	 * to for debugging this process.
-	 */
-	puts("loaded at:     "); puthex(load_addr);
-	puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
-	if ( (unsigned long)load_addr != (unsigned long)&start ) {
-		puts("relocated to:  "); puthex((unsigned long)&start);
-		puts(" ");
-		puthex((unsigned long)((unsigned long)&start + (4*num_words)));
-		puts("\n");
-	}
-
-	if (residual) {
-		/*
-		 * Tell the user where the residual data is.
-		 */
-		puts("board data at: "); puthex((unsigned long)residual);
-		puts(" ");
-		puthex((unsigned long)((unsigned long)residual +
-					sizeof(RESIDUAL)));
-		puts("\nrelocated to:  ");puthex((unsigned long)hold_residual);
-		puts(" ");
-		puthex((unsigned long)((unsigned long)hold_residual +
-					sizeof(RESIDUAL)));
-		puts("\n");
-
-		/* Is this Motorola PPCBug? */
-		if ((1 & residual->VitalProductData.FirmwareSupports) &&
-		    (1 == residual->VitalProductData.FirmwareSupplier)) {
-			unsigned char base_mod;
-			unsigned char board_type = inb(0x800) & 0xF0;
-
-			/*
-			 * Reset the onboard 21x4x Ethernet
-			 * Motorola Ethernet is at IDSEL 14 (devfn 0x70)
-			 */
-			pci_read_config_32(0x70, 0x00, &pci_viddid);
-			pci_did = (pci_viddid & 0xffff0000) >> 16;
-			/* Be sure we've really found a 21x4x chip */
-			if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_DEC) &&
-				((pci_did == PCI_DEVICE_ID_DEC_TULIP_FAST) ||
-				(pci_did == PCI_DEVICE_ID_DEC_TULIP) ||
-				(pci_did == PCI_DEVICE_ID_DEC_TULIP_PLUS) ||
-				(pci_did == PCI_DEVICE_ID_DEC_21142))) {
-				pci_read_config_32(0x70,
-						0x10,
-						&tulip_pci_base);
-				/* Get the physical base address */
-				tulip_base =
-					(tulip_pci_base & ~0x03UL) + 0x80000000;
-				/* Strobe the 21x4x reset bit in CSR0 */
-				writel(0x1, tulip_base);
-			}
-
-			/* If this is genesis 2 board then check for no
-			 * keyboard controller and more than one processor.
-			 */
-			if (board_type == 0xe0) {
-				base_mod = inb(0x803);
-				/* if a MVME2300/2400 or a Sitka then no keyboard */
-				if((base_mod == 0xFA) || (base_mod == 0xF9) ||
-				   (base_mod == 0xE1)) {
-					keyb_present = 0;	/* no keyboard */
-				}
-			}
-			/* If this is a multiprocessor system then
-			 * park the other processor so that the
-			 * kernel knows where to find them.
-			 */
-			if (residual->MaxNumCpus > 1)
-				start_multi = 1;
-		}
-		memcpy(hold_residual,residual,sizeof(RESIDUAL));
-	} else {
-		/* Tell the user we didn't find anything. */
-		puts("No residual data found.\n");
-        }
-
-	/* First, figure out what kind of host bridge we are on.  If it's
-	 * an MPC10x, we can ask it directly how much memory it has.
-	 * Otherwise, see if the residual data has anything.  This isn't
-	 * the best way, but it can be the only way.  If there's nothing,
-	 * assume 32MB. -- Tom.
-	 */
-	/* See what our host bridge is. */
-	pci_read_config_32(0x00, 0x00, &pci_viddid);
-	pci_did = (pci_viddid & 0xffff0000) >> 16;
-	/* See if we are on an MPC10x. */
-	if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA)
-			&& ((pci_did == PCI_DEVICE_ID_MOTOROLA_MPC105)
-				|| (pci_did == PCI_DEVICE_ID_MOTOROLA_MPC106)
-				|| (pci_did == PCI_DEVICE_ID_MOTOROLA_MPC107)))
-		TotalMemory = get_mem_size();
-	/* If it's not, see if we have anything in the residual data. */
-	else if (residual && residual->TotalMemory)
-		TotalMemory = residual->TotalMemory;
-	else if (OFW_interface) {
-		/*
-		 * This is a 'best guess' check.  We want to make sure
-		 * we don't try this on a PReP box without OF
-		 *     -- Cort
-		 */
-		while (OFW_interface)
-		{
-			phandle dev_handle;
-			int mem_info[2];
-
-			/* get handle to memory description */
-			if (!(dev_handle = finddevice("/memory@0")))
-				break;
-
-			/* get the info */
-			if (getprop(dev_handle, "reg", mem_info,
-						sizeof(mem_info)) != 8)
-				break;
-
-			TotalMemory = mem_info[1];
-			break;
-		}
-	} else
-		/* Fall back to hard-coding 32MB. */
-		TotalMemory = 32*1024*1024;
-
-
-	/* assume the chunk below 8M is free */
-	end_avail = (char *)0x00800000;
-
-	/*
-	 * We link ourself to 0x00800000.  When we run, we relocate
-	 * ourselves there.  So we just need __image_begin for the
-	 * start. -- Tom
-	 */
-	zimage_start = (char *)(unsigned long)(&__image_begin);
-	zimage_size = (unsigned long)(&__image_end) -
-			(unsigned long)(&__image_begin);
-
-	initrd_size = (unsigned long)(&__ramdisk_end) -
-		(unsigned long)(&__ramdisk_begin);
-
-	/*
-	 * The zImage and initrd will be between start and _end, so they've
-	 * already been moved once.  We're good to go now. -- Tom
-	 */
-	avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
-	puts("zimage at:     "); puthex((unsigned long)zimage_start);
-	puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
-	puts("\n");
-
-	if ( initrd_size ) {
-		puts("initrd at:     ");
-		puthex((unsigned long)(&__ramdisk_begin));
-		puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
-	}
-
-	avail_ram = (char *)0x00400000;
-	end_avail = (char *)0x00800000;
-	puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
-	puthex((unsigned long)end_avail); puts("\n");
-
-	if (keyb_present)
-		CRT_tstc();  /* Forces keyboard to be initialized */
-
-	puts("\nLinux/PPC load: ");
-	cp = cmd_line;
-	memcpy (cmd_line, cmd_preset, sizeof(cmd_preset));
-	while ( *cp )
-		putc(*cp++);
-	while (timer++ < 5*1000) {
-		if (tstc()) {
-			while ((ch = getc()) != '\n' && ch != '\r') {
-				/* Test for backspace/delete */
-				if (ch == '\b' || ch == '\177') {
-					if (cp != cmd_line) {
-						cp--;
-						puts("\b \b");
-					}
-				/* Test for ^x/^u (and wipe the line) */
-				} else if (ch == '\030' || ch == '\025') {
-					while (cp != cmd_line) {
-						cp--;
-						puts("\b \b");
-					}
-				} else {
-					*cp++ = ch;
-					putc(ch);
-				}
-			}
-			break;  /* Exit 'timer' loop */
-		}
-		udelay(1000);  /* 1 msec */
-	}
-	*cp = 0;
-	puts("\nUncompressing Linux...");
-
-	/*
-	 * If we have OF, then we have deferred setting the MSR.
-	 * We must set it now because we are about to overwrite
-	 * the exception table.  The new MSR value will disable
-	 * machine check exceptions and point the exception table
-	 * to the ROM.
-	 */
-	if (OFW_interface) {
-		mtmsr(MSR_IP | MSR_FP);
-		asm volatile("isync");
-	}
-
-	gunzip(0, 0x400000, zimage_start, &zimage_size);
-	puts("done.\n");
-
-	if (start_multi) {
-		puts("Parking cpu1 at 0xc0\n");
-		residual->VitalProductData.SmpIar = (unsigned long)0xc0;
-		residual->Cpus[1].CpuState = CPU_GOOD;
-		hold_residual->VitalProductData.Reserved5 = 0xdeadbeef;
-	}
-
-	{
-		struct bi_record *rec;
-		unsigned long initrd_loc;
-		unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
-				(1 << 20) - 1, (1 << 20));
-		
-		rec = (struct bi_record *)rec_loc;
-
-		/* We need to make sure that the initrd and bi_recs do not
-		 * overlap. */
-		if ( initrd_size ) {
-			initrd_loc = (unsigned long)(&__ramdisk_begin);
-			/* If the bi_recs are in the middle of the current
-			 * initrd, move the initrd to the next MB
-			 * boundary. */
-			if ((rec_loc > initrd_loc) &&
-					((initrd_loc + initrd_size)
-					 > rec_loc)) {
-				initrd_loc = _ALIGN((unsigned long)(zimage_size)
-						+ (2 << 20) - 1, (2 << 20));
-			 	memmove((void *)initrd_loc, &__ramdisk_begin,
-					 initrd_size);
-		         	puts("initrd moved:  "); puthex(initrd_loc);
-			 	puts(" "); puthex(initrd_loc + initrd_size);
-			 	puts("\n");
-			}
-		}
-
-		rec->tag = BI_FIRST;
-		rec->size = sizeof(struct bi_record);
-		rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-		rec->tag = BI_BOOTLOADER_ID;
-		memcpy( (void *)rec->data, "prepboot", 9);
-		rec->size = sizeof(struct bi_record) + 8 + 1;
-		rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-		rec->tag = BI_MACHTYPE;
-		rec->data[0] = _MACH_prep;
-		rec->data[1] = 0;
-		rec->size = sizeof(struct bi_record) + 2 *
-			sizeof(unsigned long);
-		rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-		rec->tag = BI_MEMSIZE;
-		rec->data[0] = TotalMemory;
-		rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
-		rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-		rec->tag = BI_CMD_LINE;
-		memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
-		rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
-		rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-		if ( initrd_size ) {
-			rec->tag = BI_INITRD;
-			rec->data[0] = initrd_loc;
-			rec->data[1] = initrd_size;
-			rec->size = sizeof(struct bi_record) + 2 *
-				sizeof(unsigned long);
-			rec = (struct bi_record *)((unsigned long)rec +
-					rec->size);
-		}
-
-		rec->tag = BI_LAST;
-		rec->size = sizeof(struct bi_record);
-		rec = (struct bi_record *)((unsigned long)rec + rec->size);
-	}
-	puts("Now booting the kernel\n");
-	return (unsigned long)hold_residual;
-}
diff -Nru a/arch/ppc/boot/prep/vreset.c b/arch/ppc/boot/prep/vreset.c
--- a/arch/ppc/boot/prep/vreset.c	Sat Apr  3 19:38:40 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,805 +0,0 @@
-/*
- * vreset.c
- *
- * Initialize the VGA control registers to 80x25 text mode.
- *
- * Adapted from a program by:
- *                                      Steve Sellgren
- *                                      San Francisco Indigo Company
- *                                      sfindigo!sellgren@uunet.uu.net
- *
- * Original concept by:
- *                                      Gary Thomas <gdt@linuxppc.org>
- * Adapted for Moto boxes by:
- *                                      Pat Kane & Mark Scott, 1996
- * Adapted for IBM portables by:
- *                                      Takeshi Ishimoto
- * Multi-console support:
- *                                      Terje Malmedal <terje.malmedal@usit.uio.no>
- */
-
-#include "iso_font.h"
-#include "nonstdio.h"
-
-extern char *vidmem;
-extern int lines, cols;
-struct VaRegs;
-
-/*
- * VGA Register
- */
-struct VgaRegs
-{
-	unsigned short io_port;
-	unsigned char  io_index;
-	unsigned char  io_value;
-};
-
-void unlockVideo(int slot);
-void setTextRegs(struct VgaRegs *svp);
-void setTextCLUT(int shift);
-void clearVideoMemory(void);
-void loadFont(unsigned char *ISA_mem);
-
-static void mdelay(int ms)
-{
-	for (; ms > 0; --ms)
-		udelay(1000);
-}
-
-/*
- * Default console text mode registers  used to reset
- * graphics adapter.
- */
-#define NREGS 54
-#define ENDMK  0xFFFF  /* End marker */
-
-#define S3Vendor	0x5333
-#define CirrusVendor    0x1013
-#define DiamondVendor   0x100E
-#define MatroxVendor    0x102B
-#define ParadiseVendor  0x101C
-
-struct VgaRegs GenVgaTextRegs[NREGS+1] = {
-	/* port		index	value  */
-	/* SR Regs */
-	{ 0x3c4,	0x1,	0x0 },
-	{ 0x3c4,	0x2,	0x3 },
-	{ 0x3c4,	0x3,	0x0 },
-	{ 0x3c4,	0x4,	0x2 },
-	 /* CR Regs */
-	{ 0x3d4,	0x0,	0x5f },
-	{ 0x3d4,	0x1,	0x4f },
-	{ 0x3d4,	0x2,	0x50 },
-	{ 0x3d4,	0x3,	0x82 },
-	{ 0x3d4,	0x4,	0x55 },
-	{ 0x3d4,	0x5,	0x81 },
-	{ 0x3d4,	0x6,	0xbf },
-	{ 0x3d4,	0x7,	0x1f },
-	{ 0x3d4,	0x8,	0x00 },
-	{ 0x3d4,	0x9,	0x4f },
-	{ 0x3d4,	0xa,	0x0d },
-	{ 0x3d4,	0xb,	0x0e },
-	{ 0x3d4,	0xc,	0x00 },
-	{ 0x3d4,	0xd,	0x00 },
-	{ 0x3d4,	0xe,	0x00 },
-	{ 0x3d4,	0xf,	0x00 },
-	{ 0x3d4,	0x10,	0x9c },
-	{ 0x3d4,	0x11,	0x8e },
-	{ 0x3d4,	0x12,	0x8f },
-	{ 0x3d4,	0x13,	0x28 },
-	{ 0x3d4,	0x14,	0x1f },
-	{ 0x3d4,	0x15,	0x96 },
-	{ 0x3d4,	0x16,	0xb9 },
-	{ 0x3d4,	0x17,	0xa3 },
-	 /* GR Regs */
-	{ 0x3ce,	0x0,	0x0 },
-	{ 0x3ce,	0x1,	0x0 },
-	{ 0x3ce,	0x2,	0x0 },
-	{ 0x3ce,	0x3,	0x0 },
-	{ 0x3ce,	0x4,	0x0 },
-	{ 0x3ce,	0x5,	0x10 },
-	{ 0x3ce,	0x6,	0xe },
-	{ 0x3ce,	0x7,	0x0 },
-	{ 0x3ce,	0x8,	0xff },
-	{ ENDMK }
-};
-
-struct RGBColors
-{
-  unsigned char r, g, b;
-};
-
-/*
- * Default console text mode color table.
- * These values were obtained by booting Linux with
- * text mode firmware & then dumping the registers.
- */
-struct RGBColors TextCLUT[256] =
-{
-	/* red	green	blue  */
-	{ 0x0,	0x0,	0x0 },
-	{ 0x0,	0x0,	0x2a },
-	{ 0x0,	0x2a,	0x0 },
-	{ 0x0,	0x2a,	0x2a },
-	{ 0x2a,	0x0,	0x0 },
-	{ 0x2a,	0x0,	0x2a },
-	{ 0x2a,	0x2a,	0x0 },
-	{ 0x2a,	0x2a,	0x2a },
-	{ 0x0,	0x0,	0x15 },
-	{ 0x0,	0x0,	0x3f },
-	{ 0x0,	0x2a,	0x15 },
-	{ 0x0,	0x2a,	0x3f },
-	{ 0x2a,	0x0,	0x15 },
-	{ 0x2a,	0x0,	0x3f },
-	{ 0x2a,	0x2a,	0x15 },
-	{ 0x2a,	0x2a,	0x3f },
-	{ 0x0,	0x15,	0x0 },
-	{ 0x0,	0x15,	0x2a },
-	{ 0x0,	0x3f,	0x0 },
-	{ 0x0,	0x3f,	0x2a },
-	{ 0x2a,	0x15,	0x0 },
-	{ 0x2a,	0x15,	0x2a },
-	{ 0x2a,	0x3f,	0x0 },
-	{ 0x2a,	0x3f,	0x2a },
-	{ 0x0,	0x15,	0x15 },
-	{ 0x0,	0x15,	0x3f },
-	{ 0x0,	0x3f,	0x15 },
-	{ 0x0,	0x3f,	0x3f },
-	{ 0x2a,	0x15,	0x15 },
-	{ 0x2a,	0x15,	0x3f },
-	{ 0x2a,	0x3f,	0x15 },
-	{ 0x2a,	0x3f,	0x3f },
-	{ 0x15,	0x0,	0x0 },
-	{ 0x15,	0x0,	0x2a },
-	{ 0x15,	0x2a,	0x0 },
-	{ 0x15,	0x2a,	0x2a },
-	{ 0x3f,	0x0,	0x0 },
-	{ 0x3f,	0x0,	0x2a },
-	{ 0x3f,	0x2a,	0x0 },
-	{ 0x3f,	0x2a,	0x2a },
-	{ 0x15,	0x0,	0x15 },
-	{ 0x15,	0x0,	0x3f },
-	{ 0x15,	0x2a,	0x15 },
-	{ 0x15,	0x2a,	0x3f },
-	{ 0x3f,	0x0,	0x15 },
-	{ 0x3f,	0x0,	0x3f },
-	{ 0x3f,	0x2a,	0x15 },
-	{ 0x3f,	0x2a,	0x3f },
-	{ 0x15,	0x15,	0x0 },
-	{ 0x15,	0x15,	0x2a },
-	{ 0x15,	0x3f,	0x0 },
-	{ 0x15,	0x3f,	0x2a },
-	{ 0x3f,	0x15,	0x0 },
-	{ 0x3f,	0x15,	0x2a },
-	{ 0x3f,	0x3f,	0x0 },
-	{ 0x3f,	0x3f,	0x2a },
-	{ 0x15,	0x15,	0x15 },
-	{ 0x15,	0x15,	0x3f },
-	{ 0x15,	0x3f,	0x15 },
-	{ 0x15,	0x3f,	0x3f },
-	{ 0x3f,	0x15,	0x15 },
-	{ 0x3f,	0x15,	0x3f },
-	{ 0x3f,	0x3f,	0x15 },
-	{ 0x3f,	0x3f,	0x3f },
-	{ 0x39,	0xc,	0x5 },
-	{ 0x15,	0x2c,	0xf },
-	{ 0x26,	0x10,	0x3d },
-	{ 0x29,	0x29,	0x38 },
-	{ 0x4,	0x1a,	0xe },
-	{ 0x2,	0x1e,	0x3a },
-	{ 0x3c,	0x25,	0x33 },
-	{ 0x3c,	0xc,	0x2c },
-	{ 0x3f,	0x3,	0x2b },
-	{ 0x1c,	0x9,	0x13 },
-	{ 0x25,	0x2a,	0x35 },
-	{ 0x1e,	0xa,	0x38 },
-	{ 0x24,	0x8,	0x3 },
-	{ 0x3,	0xe,	0x36 },
-	{ 0xc,	0x6,	0x2a },
-	{ 0x26,	0x3,	0x32 },
-	{ 0x5,	0x2f,	0x33 },
-	{ 0x3c,	0x35,	0x2f },
-	{ 0x2d,	0x26,	0x3e },
-	{ 0xd,	0xa,	0x10 },
-	{ 0x25,	0x3c,	0x11 },
-	{ 0xd,	0x4,	0x2e },
-	{ 0x5,	0x19,	0x3e },
-	{ 0xc,	0x13,	0x34 },
-	{ 0x2b,	0x6,	0x24 },
-	{ 0x4,	0x3,	0xd },
-	{ 0x2f,	0x3c,	0xc },
-	{ 0x2a,	0x37,	0x1f },
-	{ 0xf,	0x12,	0x38 },
-	{ 0x38,	0xe,	0x2a },
-	{ 0x12,	0x2f,	0x19 },
-	{ 0x29,	0x2e,	0x31 },
-	{ 0x25,	0x13,	0x3e },
-	{ 0x33,	0x3e,	0x33 },
-	{ 0x1d,	0x2c,	0x25 },
-	{ 0x15,	0x15,	0x5 },
-	{ 0x32,	0x25,	0x39 },
-	{ 0x1a,	0x7,	0x1f },
-	{ 0x13,	0xe,	0x1d },
-	{ 0x36,	0x17,	0x34 },
-	{ 0xf,	0x15,	0x23 },
-	{ 0x2,	0x35,	0xd },
-	{ 0x15,	0x3f,	0xc },
-	{ 0x14,	0x2f,	0xf },
-	{ 0x19,	0x21,	0x3e },
-	{ 0x27,	0x11,	0x2f },
-	{ 0x38,	0x3f,	0x3c },
-	{ 0x36,	0x2d,	0x15 },
-	{ 0x16,	0x17,	0x2 },
-	{ 0x1,	0xa,	0x3d },
-	{ 0x1b,	0x11,	0x3f },
-	{ 0x21,	0x3c,	0xd },
-	{ 0x1a,	0x39,	0x3d },
-	{ 0x8,	0xe,	0xe },
-	{ 0x22,	0x21,	0x23 },
-	{ 0x1e,	0x30,	0x5 },
-	{ 0x1f,	0x22,	0x3d },
-	{ 0x1e,	0x2f,	0xa },
-	{ 0x0,	0x1c,	0xe },
-	{ 0x0,	0x1c,	0x15 },
-	{ 0x0,	0x1c,	0x1c },
-	{ 0x0,	0x15,	0x1c },
-	{ 0x0,	0xe,	0x1c },
-	{ 0x0,	0x7,	0x1c },
-	{ 0xe,	0xe,	0x1c },
-	{ 0x11,	0xe,	0x1c },
-	{ 0x15,	0xe,	0x1c },
-	{ 0x18,	0xe,	0x1c },
-	{ 0x1c,	0xe,	0x1c },
-	{ 0x1c,	0xe,	0x18 },
-	{ 0x1c,	0xe,	0x15 },
-	{ 0x1c,	0xe,	0x11 },
-	{ 0x1c,	0xe,	0xe },
-	{ 0x1c,	0x11,	0xe },
-	{ 0x1c,	0x15,	0xe },
-	{ 0x1c,	0x18,	0xe },
-	{ 0x1c,	0x1c,	0xe },
-	{ 0x18,	0x1c,	0xe },
-	{ 0x15,	0x1c,	0xe },
-	{ 0x11,	0x1c,	0xe },
-	{ 0xe,	0x1c,	0xe },
-	{ 0xe,	0x1c,	0x11 },
-	{ 0xe,	0x1c,	0x15 },
-	{ 0xe,	0x1c,	0x18 },
-	{ 0xe,	0x1c,	0x1c },
-	{ 0xe,	0x18,	0x1c },
-	{ 0xe,	0x15,	0x1c },
-	{ 0xe,	0x11,	0x1c },
-	{ 0x14,	0x14,	0x1c },
-	{ 0x16,	0x14,	0x1c },
-	{ 0x18,	0x14,	0x1c },
-	{ 0x1a,	0x14,	0x1c },
-	{ 0x1c,	0x14,	0x1c },
-	{ 0x1c,	0x14,	0x1a },
-	{ 0x1c,	0x14,	0x18 },
-	{ 0x1c,	0x14,	0x16 },
-	{ 0x1c,	0x14,	0x14 },
-	{ 0x1c,	0x16,	0x14 },
-	{ 0x1c,	0x18,	0x14 },
-	{ 0x1c,	0x1a,	0x14 },
-	{ 0x1c,	0x1c,	0x14 },
-	{ 0x1a,	0x1c,	0x14 },
-	{ 0x18,	0x1c,	0x14 },
-	{ 0x16,	0x1c,	0x14 },
-	{ 0x14,	0x1c,	0x14 },
-	{ 0x14,	0x1c,	0x16 },
-	{ 0x14,	0x1c,	0x18 },
-	{ 0x14,	0x1c,	0x1a },
-	{ 0x14,	0x1c,	0x1c },
-	{ 0x14,	0x1a,	0x1c },
-	{ 0x14,	0x18,	0x1c },
-	{ 0x14,	0x16,	0x1c },
-	{ 0x0,	0x0,	0x10 },
-	{ 0x4,	0x0,	0x10 },
-	{ 0x8,	0x0,	0x10 },
-	{ 0xc,	0x0,	0x10 },
-	{ 0x10,	0x0,	0x10 },
-	{ 0x10,	0x0,	0xc },
-	{ 0x10,	0x0,	0x8 },
-	{ 0x10,	0x0,	0x4 },
-	{ 0x10,	0x0,	0x0 },
-	{ 0x10,	0x4,	0x0 },
-	{ 0x10,	0x8,	0x0 },
-	{ 0x10,	0xc,	0x0 },
-	{ 0x10,	0x10,	0x0 },
-	{ 0xc,	0x10,	0x0 },
-	{ 0x8,	0x10,	0x0 },
-	{ 0x4,	0x10,	0x0 },
-	{ 0x0,	0x10,	0x0 },
-	{ 0x0,	0x10,	0x4 },
-	{ 0x0,	0x10,	0x8 },
-	{ 0x0,	0x10,	0xc },
-	{ 0x0,	0x10,	0x10 },
-	{ 0x0,	0xc,	0x10 },
-	{ 0x0,	0x8,	0x10 },
-	{ 0x0,	0x4,	0x10 },
-	{ 0x8,	0x8,	0x10 },
-	{ 0xa,	0x8,	0x10 },
-	{ 0xc,	0x8,	0x10 },
-	{ 0xe,	0x8,	0x10 },
-	{ 0x10,	0x8,	0x10 },
-	{ 0x10,	0x8,	0xe },
-	{ 0x10,	0x8,	0xc },
-	{ 0x10,	0x8,	0xa },
-	{ 0x10,	0x8,	0x8 },
-	{ 0x10,	0xa,	0x8 },
-	{ 0x10,	0xc,	0x8 },
-	{ 0x10,	0xe,	0x8 },
-	{ 0x10,	0x10,	0x8 },
-	{ 0xe,	0x10,	0x8 },
-	{ 0xc,	0x10,	0x8 },
-	{ 0xa,	0x10,	0x8 },
-	{ 0x8,	0x10,	0x8 },
-	{ 0x8,	0x10,	0xa },
-	{ 0x8,	0x10,	0xc },
-	{ 0x8,	0x10,	0xe },
-	{ 0x8,	0x10,	0x10 },
-	{ 0x8,	0xe,	0x10 },
-	{ 0x8,	0xc,	0x10 },
-	{ 0x8,	0xa,	0x10 },
-	{ 0xb,	0xb,	0x10 },
-	{ 0xc,	0xb,	0x10 },
-	{ 0xd,	0xb,	0x10 },
-	{ 0xf,	0xb,	0x10 },
-	{ 0x10,	0xb,	0x10 },
-	{ 0x10,	0xb,	0xf },
-	{ 0x10,	0xb,	0xd },
-	{ 0x10,	0xb,	0xc },
-	{ 0x10,	0xb,	0xb },
-	{ 0x10,	0xc,	0xb },
-	{ 0x10,	0xd,	0xb },
-	{ 0x10,	0xf,	0xb },
-	{ 0x10,	0x10,	0xb },
-	{ 0xf,	0x10,	0xb },
-	{ 0xd,	0x10,	0xb },
-	{ 0xc,	0x10,	0xb },
-	{ 0xb,	0x10,	0xb },
-	{ 0xb,	0x10,	0xc },
-	{ 0xb,	0x10,	0xd },
-	{ 0xb,	0x10,	0xf },
-	{ 0xb,	0x10,	0x10 },
-	{ 0xb,	0xf,	0x10 },
-	{ 0xb,	0xd,	0x10 },
-	{ 0xb,	0xc,	0x10 },
-	{ 0x0,	0x0,	0x0 },
-	{ 0x0,	0x0,	0x0 },
-	{ 0x0,	0x0,	0x0 },
-	{ 0x0,	0x0,	0x0 },
-	{ 0x0,	0x0,	0x0 },
-	{ 0x0,	0x0,	0x0 },
-	{ 0x0,	0x0,	0x0 }
-};
-
-unsigned char AC[21] = {
-    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
-    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
-    0x0C, 0x00, 0x0F, 0x08, 0x00};
-
-static int scanPCI(int start_slt);
-static int PCIVendor(int);
-#ifdef DEBUG
-static void printslots(void);
-#endif
-extern void puthex(unsigned long);
-extern void puts(const char *);
-static void unlockS3(void);
-
-static inline void
-outw(int port, unsigned short val)
-{
-	outb(port, val >> 8);
-	outb(port+1, val);
-}
-
-int
-vga_init(unsigned char *ISA_mem)
-{
-	int slot;
-	struct VgaRegs *VgaTextRegs;
-
-	/* See if VGA already in TEXT mode - exit if so! */
-	outb(0x3CE, 0x06);
-	if ((inb(0x3CF) & 0x01) == 0){
-		puts("VGA already in text mode\n");
-		return 0;
-	}
-
-	/* If no VGA responding in text mode, then we have some work to do...
-	 */
-	slot = -1;
-	while((slot = scanPCI(slot)) > -1) { /* find video card in use  */
-		unlockVideo(slot);           /* enable I/O to card      */
-		VgaTextRegs = GenVgaTextRegs;
-
-		switch (PCIVendor(slot)) {
-		default:
-			break;
-		case(S3Vendor):
-			unlockS3();
-			break;
-
-		case(CirrusVendor):
-			outw(0x3C4, 0x0612);       /* unlock ext regs */
-			outw(0x3C4, 0x0700);       /* reset ext sequence mode */
-			break;
-
-		case(ParadiseVendor):                 /* IBM Portable 850 */
-			outw(0x3ce, 0x0f05);      /* unlock pardise registers */
-			outw(0x3c4, 0x0648);
-			outw(0x3d4, 0x2985);
-			outw(0x3d4, 0x34a6);
-			outb(0x3ce, 0x0b);       /* disable linear addressing */
-			outb(0x3cf, inb(0x3cf) & ~0x30);
-			outw(0x3c4, 0x1400);
-			outb(0x3ce, 0x0e);       /* disable 256 color mode */
-			outb(0x3cf, inb(0x3cf) & ~0x01);
-			outb(0xd00, 0xff);       /* enable auto-centering */
-			if (!(inb(0xd01) & 0x03)) {
-				outb(0x3d4, 0x33);
-				outb(0x3d5, inb(0x3d5) & ~0x90);
-				outb(0x3d4, 0x32);
-				outb(0x3d5, inb(0x3d5) | 0x04);
-				outw(0x3d4, 0x0250);
-				outw(0x3d4, 0x07ba);
-				outw(0x3d4, 0x0900);
-				outw(0x3d4, 0x15e7);
-				outw(0x3d4, 0x2a95);
-			}
-			outw(0x3d4, 0x34a0);
-			break;
-
-	#if 0 /* Untested - probably doesn't work */
-		case(MatroxVendor):
-		case(DiamondVendor):
-			puts("VGA Chip Vendor ID: ");
-			puthex(PCIVendor(slot));
-			puts("\n");
-			mdelay(1000);
-	#endif
-		};
-
-		outw(0x3C4, 0x0120);           /* disable video              */
-		setTextRegs(VgaTextRegs);      /* initial register setup     */
-		setTextCLUT(0);                /* load color lookup table    */
-		loadFont(ISA_mem);             /* load font                  */
-		setTextRegs(VgaTextRegs);      /* reload registers           */
-		outw(0x3C4, 0x0100);           /* re-enable video            */
-		clearVideoMemory();
-
-		if (PCIVendor(slot) == S3Vendor) {
-			outb(0x3c2, 0x63);                  /* MISC */
-		} /* endif */
-
-	#ifdef DEBUG
-		printslots();
-		mdelay(5000);
-	#endif
-
-		mdelay(1000);	/* give time for the video monitor to come up */
-        }
-	return (1);  /* 'CRT' I/O supported */
-}
-
-/*
- * Write to VGA Attribute registers.
- */
-void
-writeAttr(unsigned char index, unsigned char data, unsigned char videoOn)
-{
-	unsigned char v;
-	v = inb(0x3da);   /* reset attr. address toggle */
-	if (videoOn)
-		outb(0x3c0, (index & 0x1F) | 0x20);
-	else
-		outb(0x3c0, (index & 0x1F));
-	outb(0x3c0, data);
-}
-
-void
-setTextRegs(struct VgaRegs *svp)
-{
-	int i;
-
-	/*
-	 *  saved settings
-	 */
-	while( svp->io_port != ENDMK ) {
-		outb(svp->io_port,   svp->io_index);
-		outb(svp->io_port+1, svp->io_value);
-		svp++;
-	}
-
-	outb(0x3c2, 0x67);  /* MISC */
-	outb(0x3c6, 0xff);  /* MASK */
-
-	for ( i = 0; i < 0x10; i++)
-		writeAttr(i, AC[i], 0);  /* pallete */
-	writeAttr(0x10, 0x0c, 0);    /* text mode */
-	writeAttr(0x11, 0x00, 0);    /* overscan color (border) */
-	writeAttr(0x12, 0x0f, 0);    /* plane enable */
-	writeAttr(0x13, 0x08, 0);    /* pixel panning */
-	writeAttr(0x14, 0x00, 1);    /* color select; video on  */
-}
-
-void
-setTextCLUT(int shift)
-{
-	int i;
-
-	outb(0x3C6, 0xFF);
-	i = inb(0x3C7);
-	outb(0x3C8, 0);
-	i = inb(0x3C7);
-
-	for ( i = 0; i < 256; i++) {
-		outb(0x3C9, TextCLUT[i].r << shift);
-		outb(0x3C9, TextCLUT[i].g << shift);
-		outb(0x3C9, TextCLUT[i].b << shift);
-	}
-}
-
-void
-loadFont(unsigned char *ISA_mem)
-{
-	int i, j;
-	unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
-
-	outb(0x3C2, 0x67);
-	/*
-	 * Load font
-	 */
-	i = inb(0x3DA);  /* Reset Attr toggle */
-
-	outb(0x3C0,0x30);
-	outb(0x3C0, 0x01);      /* graphics mode */
-
-	outw(0x3C4, 0x0001);    /* reset sequencer */
-	outw(0x3C4, 0x0204);    /* write to plane 2 */
-	outw(0x3C4, 0x0406);    /* enable plane graphics */
-	outw(0x3C4, 0x0003);    /* reset sequencer */
-	outw(0x3CE, 0x0402);    /* read plane 2 */
-	outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
-	outw(0x3CE, 0x0605);    /* set graphics mode */
-
-	for (i = 0;  i < sizeof(font);  i += 16) {
-		for (j = 0;  j < 16;  j++) {
-			__asm__ volatile("eieio");
-			font_page[(2*i)+j] = font[i+j];
-		}
-	}
-}
-
-static void
-unlockS3(void)
-{
-        int s3_device_id;
-	outw(0x3d4, 0x3848);
-	outw(0x3d4, 0x39a5);
-	outb(0x3d4, 0x2d);
-	s3_device_id = inb(0x3d5) << 8;
-	outb(0x3d4, 0x2e);
-	s3_device_id |= inb(0x3d5);
-
-	if (s3_device_id != 0x8812) {
-		/* From the S3 manual */
-		outb(0x46E8, 0x10);  /* Put into setup mode */
-		outb(0x3C3, 0x10);
-		outb(0x102, 0x01);   /* Enable registers */
-		outb(0x46E8, 0x08);  /* Enable video */
-		outb(0x3C3, 0x08);
-		outb(0x4AE8, 0x00);
-
-#if 0
-		outb(0x42E8, 0x80);  /* Reset graphics engine? */
-#endif
-
-		outb(0x3D4, 0x38);  /* Unlock all registers */
-		outb(0x3D5, 0x48);
-		outb(0x3D4, 0x39);
-		outb(0x3D5, 0xA5);
-		outb(0x3D4, 0x40);
-		outb(0x3D5, inb(0x3D5)|0x01);
-		outb(0x3D4, 0x33);
-		outb(0x3D5, inb(0x3D5)&~0x52);
-		outb(0x3D4, 0x35);
-		outb(0x3D5, inb(0x3D5)&~0x30);
-		outb(0x3D4, 0x3A);
-		outb(0x3D5, 0x00);
-		outb(0x3D4, 0x53);
-		outb(0x3D5, 0x00);
-		outb(0x3D4, 0x31);
-		outb(0x3D5, inb(0x3D5)&~0x4B);
-		outb(0x3D4, 0x58);
-
-		outb(0x3D5, 0);
-
-		outb(0x3D4, 0x54);
-		outb(0x3D5, 0x38);
-		outb(0x3D4, 0x60);
-		outb(0x3D5, 0x07);
-		outb(0x3D4, 0x61);
-		outb(0x3D5, 0x80);
-		outb(0x3D4, 0x62);
-		outb(0x3D5, 0xA1);
-		outb(0x3D4, 0x69);  /* High order bits for cursor address */
-		outb(0x3D5, 0);
-
-		outb(0x3D4, 0x32);
-		outb(0x3D5, inb(0x3D5)&~0x10);
-	} else {
-                outw(0x3c4, 0x0806);            /* IBM Portable 860 */
-                outw(0x3c4, 0x1041);
-                outw(0x3c4, 0x1128);
-                outw(0x3d4, 0x4000);
-                outw(0x3d4, 0x3100);
-                outw(0x3d4, 0x3a05);
-                outw(0x3d4, 0x6688);
-                outw(0x3d4, 0x5800);            /* disable linear addressing */
-                outw(0x3d4, 0x4500);            /* disable H/W cursor */
-                outw(0x3c4, 0x5410);            /* enable auto-centering */
-                outw(0x3c4, 0x561f);
-                outw(0x3c4, 0x1b80);            /* lock DCLK selection */
-                outw(0x3d4, 0x3900);            /* lock S3 registers */
-                outw(0x3d4, 0x3800);
-	} /* endif */
-}
-
-/*
- * cursor() sets an offset (0-1999) into the 80x25 text area.
- */
-void
-cursor(int x, int y)
-{
-	int pos = (y*cols)+x;
-	outb(0x3D4, 14);
-	outb(0x3D5, pos >> 8);
-	outb(0x3D4, 15);
-	outb(0x3D5, pos);
-}
-
-void
-clearVideoMemory(void)
-{
-	int i, j;
-	for (i = 0;  i < lines;  i++) {
-		for (j = 0;  j < cols;  j++) {
-			vidmem[((i*cols)+j)*2] = 0x20;	/* fill with space character */
-			vidmem[((i*cols)+j)*2+1] = 0x07;  /* set bg & fg attributes */
-		}
-	}
-}
-
-/* ============ */
-
-
-#define NSLOTS 8
-#define NPCIREGS  5
-
-
-/*
- should use devfunc number/indirect method to be totally safe on
- all machines, this works for now on 3 slot Moto boxes
-*/
-
-struct PCI_ConfigInfo {
-  unsigned long * config_addr;
-  unsigned long regs[NPCIREGS];
-} PCI_slots [NSLOTS] = {
-
-    { (unsigned long *)0x80808000, {0xDEADBEEF,} },   /* onboard */
-    { (unsigned long *)0x80800800, {0xDEADBEEF,} },   /* onboard */
-    { (unsigned long *)0x80801000, {0xDEADBEEF,} },   /* onboard */
-    { (unsigned long *)0x80802000, {0xDEADBEEF,} },   /* onboard */
-    { (unsigned long *)0x80804000, {0xDEADBEEF,} },   /* onboard */
-    { (unsigned long *)0x80810000, {0xDEADBEEF,} },   /* slot A/1 */
-    { (unsigned long *)0x80820000, {0xDEADBEEF,} },   /* slot B/2 */
-    { (unsigned long *)0x80840000, {0xDEADBEEF,} }    /* slot C/3 */
-};
-
-
-
-/*
- * The following code modifies the PCI Command register
- * to enable memory and I/O accesses.
- */
-void
-unlockVideo(int slot)
-{
-       volatile unsigned char * ppci;
-
-        ppci =  (unsigned char * )PCI_slots[slot].config_addr;
-	ppci[4] = 0x0003;         /* enable memory and I/O accesses */
-	ppci[0x10] = 0x00000;     /* turn off memory mapping */
-	ppci[0x11] = 0x00000;     /* mem_base = 0 */
-	ppci[0x12] = 0x00000;
-	ppci[0x13] = 0x00000;
-	__asm__ volatile("eieio");
-
-	outb(0x3d4, 0x11);
-	outb(0x3d5, 0x0e);   /* unlock CR0-CR7 */
-}
-
-long
-SwapBytes(long lv)   /* turn little endian into big indian long */
-{
-    long t;
-    t  = (lv&0x000000FF) << 24;
-    t |= (lv&0x0000FF00) << 8;
-    t |= (lv&0x00FF0000) >> 8;
-    t |= (lv&0xFF000000) >> 24;
-    return(t);
-}
-
-
-#define DEVID   0
-#define CMD     1
-#define CLASS   2
-#define MEMBASE 4
-
-int
-scanPCI(int start_slt)
-{
-	int slt, r;
-	struct PCI_ConfigInfo *pslot;
-	int theSlot = -1;
-	int highVgaSlot = 0;
-
-	for ( slt = start_slt + 1; slt < NSLOTS; slt++) {
-		pslot = &PCI_slots[slt];
-		for ( r = 0; r < NPCIREGS; r++) {
-			pslot->regs[r] = SwapBytes ( pslot->config_addr[r] );
-		}
-		/* card in slot ? */
-		if ( pslot->regs[DEVID] != 0xFFFFFFFF ) {
-			/* VGA ? */
-			if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) ||
-			     ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) {
-				highVgaSlot = slt;
-				/* did firmware enable it ? */
-				if ( (pslot->regs[CMD] & 0x03) ) {
-					theSlot = slt;
-					break;
-				}
-			}
-		}
-	}
-
-	return ( theSlot );
-}
-
-/* return Vendor ID of card in the slot */
-static
-int PCIVendor(int slotnum) {
- struct PCI_ConfigInfo *pslot;
-
- pslot = &PCI_slots[slotnum];
-
-return (pslot->regs[DEVID] & 0xFFFF);
-}
-
-#ifdef DEBUG
-static
-void printslots(void)
-{
-	int i;
-#if 0
-	struct PCI_ConfigInfo *pslot;
-#endif
-	for(i=0; i < NSLOTS; i++) {
-#if 0
-		pslot = &PCI_slots[i];
-		printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n",
-		       i, pslot->config_addr, pslot->regs[0], pslot->regs[2]);
-#else
-		puts("PCI Slot number: "); puthex(i);
-		puts(" Vendor ID: ");
-		puthex(PCIVendor(i)); puts("\n");
-#endif
-	}
-}
-#endif /* DEBUG */
diff -Nru a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
--- a/arch/ppc/boot/simple/Makefile	Sat Apr  3 19:38:40 2004
+++ b/arch/ppc/boot/simple/Makefile	Sat Apr  3 19:38:40 2004
@@ -26,11 +26,12 @@
 utils				:= $(boot)/utils
 bootlib				:= $(boot)/lib
 images				:= $(boot)/images
+of1275				:= $(boot)/of1275
 tftpboot			:= /tftpboot
 
 # Normally, we use the 'misc.c' file for decompress_kernel and
 # whatnot.  Sometimes we need to override this however.
-misc-y	:= misc.o ../common/bootinfo.o
+misc-y	:= misc.o
 
 # Normally, we have our images end in .elf, but something we want to
 # change this.
@@ -89,6 +90,7 @@
 
 # Overrides previous assingment
      extra.o-$(CONFIG_PPLUS)		:= legacy.o
+     extra.o-$(CONFIG_LOPEC)		:= mpc10x_memory.o
 
       zimage-$(pcore)			:= zImage-STRIPELF
 zimageinitrd-$(pcore)			:= zImage.initrd-STRIPELF
@@ -96,6 +98,12 @@
          end-$(pcore)			:= pcore
    cacheflag-$(pcore)			:= -include $(clear_L2_L3)
 
+      zimage-$(CONFIG_PPC_PREP)		:= zImage-PPLUS
+zimageinitrd-$(CONFIG_PPC_PREP)		:= zImage.initrd-PPLUS
+     extra.o-$(CONFIG_PPC_PREP)		:= legacy.o
+        misc-$(CONFIG_PPC_PREP)		+= misc-prep.o mpc10x_memory.o
+         end-$(CONFIG_PPC_PREP)		:= prep
+
          end-$(CONFIG_SANDPOINT)	:= sandpoint
    cacheflag-$(CONFIG_SANDPOINT)	:= -include $(clear_L2_L3)
 
@@ -106,7 +114,7 @@
         misc-$(CONFIG_SPRUCE)		+= misc-spruce.o
 
 # SMP images should have a '.smp' suffix.
-         end-$(CONFIG_SMP)		+= .smp
+         end-$(CONFIG_SMP)             := $(end-y).smp
 
 # This is a treeboot that needs init functions until the
 # boot rom is sorted out (i.e. this is short lived)
@@ -138,6 +146,9 @@
 endif
 
 LIBS				:= $(common)/lib.a $(bootlib)/lib.a
+ifeq ($(CONFIG_PPC_PREP),y)
+LIBS 				+= $(of1275)/lib.a
+endif
 
 OBJS				:= $(addprefix $(obj)/,$(boot-y))
 
@@ -199,10 +210,10 @@
 	$(MKTREE) $(obj)/zvmlinux.initrd $(images)/zImage.initrd.$(end-y) \
 		$(ENTRYPOINT)
 
-$(images)/zImage-PPLUS: $(obj)/zvmlinux $(MKPREP) $(MKBUGBOOT)
-	$(MKPREP) -pbp $(obj)/zvmlinux $(images)/zImage.pplus
+$(images)/zImage-PPLUS: $(obj)/zvmlinux $(utils)/mkprep $(MKBUGBOOT)
+	$(MKPREP) -pbp $(obj)/zvmlinux $(images)/zImage.$(end-y)
 	$(MKBUGBOOT) $(obj)/zvmlinux $(images)/zImage.bugboot
 
-$(images)/zImage.initrd-PPLUS: $(obj)/zvmlinux.initrd $(MKPREP) $(MKBUGBOOT)
-	$(MKPREP) -pbp $(obj)/zvmlinux.initrd $(images)/zImage.initrd.pplus
+$(images)/zImage.initrd-PPLUS: $(obj)/zvmlinux.initrd $(utils)/mkprep $(MKBUGBOOT)
+	$(MKPREP) -pbp $(obj)/zvmlinux.initrd $(images)/zImage.initrd.$(end-y)
 	$(MKBUGBOOT) $(obj)/zvmlinux.initrd $(images)/zImage.initrd.bugboot
diff -Nru a/arch/ppc/boot/simple/cpc700_memory.c b/arch/ppc/boot/simple/cpc700_memory.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/simple/cpc700_memory.c	Sat Apr  3 19:38:55 2004
@@ -0,0 +1,36 @@
+/*
+ * arch/ppc/boot/common/cpc700_memory.c
+ *
+ * Find memory based upon settings in the CPC700 bridge
+ *
+ * Author: Dan Cox
+ *
+ * 2001-2002 (c) 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.
+ */
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include "cpc700.h"
+
+unsigned long
+cpc700_get_mem_size(void)
+{
+	int i;
+	unsigned long len, amt;
+
+	/* Start at MB1EA, since MB0EA will most likely be the ending address
+	   for ROM space. */
+	for(len = 0, i = CPC700_MB1EA; i <= CPC700_MB4EA; i+=4) {
+		amt = cpc700_read_memreg(i);
+		if (amt == 0)
+			break;
+		len = amt;
+	}
+
+	return len;
+}
+
+
diff -Nru a/arch/ppc/boot/simple/head.S b/arch/ppc/boot/simple/head.S
--- a/arch/ppc/boot/simple/head.S	Sat Apr  3 19:38:45 2004
+++ b/arch/ppc/boot/simple/head.S	Sat Apr  3 19:38:45 2004
@@ -7,7 +7,7 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * 2001-2003 (c) MontaVista, Software, Inc.  This file is licensed under
+ * 2001-2004 (c) 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.
@@ -57,10 +57,11 @@
 	isync
 #endif
 
-#if defined(CONFIG_MBX) || defined(CONFIG_RPX6)
+#if defined(CONFIG_MBX) || defined(CONFIG_RPX6) || defined(CONFIG_PPC_PREP)
 	mr	r29,r3	/* On the MBX860, r3 is the board info pointer.
-			 * On the RPXSUPER, r3 points to the
-			 * NVRAM configuration keys.
+			 * On the RPXSUPER, r3 points to the NVRAM
+			 * configuration keys.
+			 * On PReP, r3 is the pointer to the residual data.
 			 */
 #endif
 
@@ -69,7 +70,36 @@
 	/* The following functions we call must not modify r3 or r4.....
 	*/
 #ifdef CONFIG_6xx
+	/* On PReP we must look at the OpenFirmware pointer and sanity
+	 * test it.  On other platforms, we disable the MMU right now
+	 * and other bits.
+	 */
+#ifdef CONFIG_PPC_PREP
+/*
+ * Save the OF pointer to r25, but only if the entry point is in a sane
+ * location; if not we store 0.  If there is no entry point, or it is
+ * invalid, we establish the default MSR value immediately.  Otherwise,
+ * we defer doing that, to allow OF functions to be called, until we
+ * begin uncompressing the kernel.
+ */
+	lis	r8,0x0fff		/* r8 = 0x0fffffff */
+	ori	r8,r8,0xffff
+
+	subc	r8,r8,r5		/* r8 = (r5 <= r8) ? ~0 : 0 */
+	subfe	r8,r8,r8
+	nand	r8,r8,r8
+
+	and.	r5,r5,r8		/* r5 will be cleared if (r5 > r8) */
+	bne+	haveOF
+
+	li	r8,MSR_IP|MSR_FP	/* Not OF: set MSR immediately */
+  	mtmsr	r8
+	isync
+haveOF:
+	mr	r25,r5
+#else
 	bl	disable_6xx_mmu
+#endif
 	bl	disable_6xx_l1cache
 
 	CLEAR_CACHES
@@ -99,7 +129,7 @@
 	mr	r3, r29
 #endif
 
-#if defined(CONFIG_MBX) || defined(CONFIG_RPX6)
+#if defined(CONFIG_MBX) || defined(CONFIG_RPX6) || defined(CONFIG_PPC_PREP)
 	mr	r4,r29	/* put the board info pointer where the relocate
 			 * routine will find it
 			 */
diff -Nru a/arch/ppc/boot/simple/misc-prep.c b/arch/ppc/boot/simple/misc-prep.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/simple/misc-prep.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,211 @@
+/*
+ * arch/ppc/boot/simple/misc-prep.c
+ *
+ * Maintainer: Tom Rini <trini@kernel.crashing.org>
+ *
+ * In the past: Gary Thomas, Cort Dougan <cort@cs.nmt.edu>
+ */
+
+#include <linux/config.h>
+#include <linux/pci_ids.h>
+#include <linux/types.h>
+#include <asm/residual.h>
+#include <asm/string.h>
+#include <asm/byteorder.h>
+#include "mpc10x.h"
+#include "of1275.h"
+#include "nonstdio.h"
+
+extern int keyb_present;	/* keyboard controller is present by default */
+RESIDUAL hold_resid_buf;
+RESIDUAL *hold_residual = &hold_resid_buf;
+static void *OFW_interface;	/* Pointer to OF, if available. */
+
+#ifdef CONFIG_VGA_CONSOLE
+char *vidmem = (char *)0xC00B8000;
+int lines = 25, cols = 80;
+int orig_x, orig_y = 24;
+#endif /* CONFIG_VGA_CONSOLE */
+
+extern int CRT_tstc(void);
+extern int vga_init(unsigned char *ISA_mem);
+extern void gunzip(void *, int, unsigned char *, int *);
+extern unsigned long serial_init(int chan, void *ignored);
+extern void serial_fixups(void);
+extern struct bi_record *decompress_kernel(unsigned long load_addr,
+		int num_words, unsigned long cksum);
+extern void disable_6xx_mmu(void);
+extern unsigned long mpc10x_get_mem_size(void);
+
+static void
+writel(unsigned int val, unsigned int address)
+{
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	*(unsigned int *)address = cpu_to_le32(val);
+}
+
+#define PCI_CFG_ADDR(dev,off)	((0x80<<24) | (dev<<8) | (off&0xfc))
+#define PCI_CFG_DATA(off)	(MPC10X_MAPA_CNFG_DATA+(off&3))
+
+static void
+pci_read_config_32(unsigned char devfn,
+		unsigned char offset,
+		unsigned int *val)
+{
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	*(unsigned int *)PCI_CFG_ADDR(devfn,offset) =
+		cpu_to_le32(MPC10X_MAPA_CNFG_ADDR);
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	*val = le32_to_cpu(*(unsigned int *)PCI_CFG_DATA(offset));
+	return;
+}
+
+#ifdef CONFIG_VGA_CONSOLE
+void
+scroll(void)
+{
+	int i;
+
+	memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
+	for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
+		vidmem[i] = ' ';
+}
+#endif /* CONFIG_VGA_CONSOLE */
+
+unsigned long
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		  RESIDUAL *residual, void *OFW)
+{
+	int start_multi = 0;
+	unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base;
+
+	/* If we have Open Firmware, initialise it immediately */
+	if (OFW) {
+		OFW_interface = OFW;
+		ofinit(OFW_interface);
+	}
+
+#if defined(CONFIG_VGA_CONSOLE)
+	vga_init((unsigned char *)0xC0000000);
+#endif /* CONFIG_VGA_CONSOLE */
+
+	if (residual) {
+		/* Is this Motorola PPCBug? */
+		if ((1 & residual->VitalProductData.FirmwareSupports) &&
+		    (1 == residual->VitalProductData.FirmwareSupplier)) {
+			unsigned char base_mod;
+			unsigned char board_type = inb(0x801) & 0xF0;
+
+			/*
+			 * Reset the onboard 21x4x Ethernet
+			 * Motorola Ethernet is at IDSEL 14 (devfn 0x70)
+			 */
+			pci_read_config_32(0x70, 0x00, &pci_viddid);
+			pci_did = (pci_viddid & 0xffff0000) >> 16;
+			/* Be sure we've really found a 21x4x chip */
+			if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_DEC) &&
+				((pci_did == PCI_DEVICE_ID_DEC_TULIP_FAST) ||
+				(pci_did == PCI_DEVICE_ID_DEC_TULIP) ||
+				(pci_did == PCI_DEVICE_ID_DEC_TULIP_PLUS) ||
+				(pci_did == PCI_DEVICE_ID_DEC_21142))) {
+				pci_read_config_32(0x70,
+						0x10,
+						&tulip_pci_base);
+				/* Get the physical base address */
+				tulip_base =
+					(tulip_pci_base & ~0x03UL) + 0x80000000;
+				/* Strobe the 21x4x reset bit in CSR0 */
+				writel(0x1, tulip_base);
+			}
+
+			/* If this is genesis 2 board then check for no
+			 * keyboard controller and more than one processor.
+			 */
+			if (board_type == 0xe0) {
+				base_mod = inb(0x803);
+				/* if a MVME2300/2400 or a Sitka then no keyboard */
+				if((base_mod == 0xFA) || (base_mod == 0xF9) ||
+				   (base_mod == 0xE1)) {
+					keyb_present = 0;	/* no keyboard */
+				}
+			}
+			/* If this is a multiprocessor system then
+			 * park the other processor so that the
+			 * kernel knows where to find them.
+			 */
+			if (residual->MaxNumCpus > 1)
+				start_multi = 1;
+		}
+		memcpy(hold_residual,residual,sizeof(RESIDUAL));
+        }
+
+	/* Call decompress_kernel */
+	decompress_kernel(load_addr, num_words, cksum);
+
+	if (start_multi) {
+		residual->VitalProductData.SmpIar = (unsigned long)0xc0;
+		residual->Cpus[1].CpuState = CPU_GOOD;
+		hold_residual->VitalProductData.Reserved5 = 0xdeadbeef;
+	}
+
+	/* Now go and clear out the BATs and ensure that our MSR is
+	 * correct .*/
+	disable_6xx_mmu();
+
+	/* Make r3 be a pointer to the residual data. */
+	return (unsigned long)hold_residual;
+}
+
+unsigned long
+get_mem_size(void)
+{
+	unsigned int pci_viddid, pci_did;
+
+	/* First, figure out what kind of host bridge we are on.  If it's
+	 * an MPC10x, we can ask it directly how much memory it has.
+	 * Otherwise, see if the residual data has anything.  This isn't
+	 * the best way, but it can be the only way.  If there's nothing,
+	 * assume 32MB. -- Tom.
+	 */
+	/* See what our host bridge is. */
+	pci_read_config_32(0x00, 0x00, &pci_viddid);
+	pci_did = (pci_viddid & 0xffff0000) >> 16;
+	/* See if we are on an MPC10x. */
+	if (((pci_viddid & 0xffff) == PCI_VENDOR_ID_MOTOROLA)
+			&& ((pci_did == PCI_DEVICE_ID_MOTOROLA_MPC105)
+				|| (pci_did == PCI_DEVICE_ID_MOTOROLA_MPC106)
+				|| (pci_did == PCI_DEVICE_ID_MOTOROLA_MPC107)))
+		return mpc10x_get_mem_size();
+	/* If it's not, see if we have anything in the residual data. */
+	else if (hold_residual && hold_residual->TotalMemory)
+		return hold_residual->TotalMemory;
+	else if (OFW_interface) {
+		/*
+		 * This is a 'best guess' check.  We want to make sure
+		 * we don't try this on a PReP box without OF
+		 *     -- Cort
+		 */
+		while (OFW_interface)
+		{
+			phandle dev_handle;
+			int mem_info[2];
+
+			/* get handle to memory description */
+			if (!(dev_handle = finddevice("/memory@0")))
+				break;
+
+			/* get the info */
+			if (getprop(dev_handle, "reg", mem_info,
+						sizeof(mem_info)) != 8)
+				break;
+
+			return mem_info[1];
+		}
+	}
+
+	/* Fall back to hard-coding 32MB. */
+	return 32*1024*1024;
+}
diff -Nru a/arch/ppc/boot/simple/misc-spruce.c b/arch/ppc/boot/simple/misc-spruce.c
--- a/arch/ppc/boot/simple/misc-spruce.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/boot/simple/misc-spruce.c	Sat Apr  3 19:38:43 2004
@@ -174,7 +174,8 @@
 }
 
 unsigned long
-load_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		void *ign1, void *ign2)
 {
 	int csr0;
 	int csr_id;
diff -Nru a/arch/ppc/boot/simple/misc.c b/arch/ppc/boot/simple/misc.c
--- a/arch/ppc/boot/simple/misc.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/boot/simple/misc.c	Sat Apr  3 19:38:55 2004
@@ -99,7 +99,9 @@
 	unsigned long initrd_loc, TotalMemory = 0;
 
 	serial_fixups();
+#ifdef CONFIG_SERIAL_8250_CONSOLE
 	com_port = serial_init(0, NULL);
+#endif
 
 #ifdef CONFIG_44x
 	/* Reset MAL */
@@ -269,7 +271,8 @@
 
 /* Allow decompress_kernel to be hooked into.  This is the default. */
 void * __attribute__ ((weak))
-load_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
+load_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
+		void *ign1, void *ign2)
 {
 		return decompress_kernel(load_addr, num_words, cksum);
 }
diff -Nru a/arch/ppc/boot/simple/mpc10x_memory.c b/arch/ppc/boot/simple/mpc10x_memory.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/simple/mpc10x_memory.c	Sat Apr  3 19:38:42 2004
@@ -0,0 +1,111 @@
+/*
+ * arch/ppc/boot/common/mpc10x_common.c
+ *
+ * A routine to find out how much memory the machine has.
+ *
+ * Based on:
+ * arch/ppc/kernel/mpc10x_common.c
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * 2001-2002 (c) 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.
+ */
+
+#include <linux/pci.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include "mpc10x.h"
+
+/*
+ * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
+ */
+
+/*
+ * PCI config space macros, similar to indirect_xxx and early_xxx macros.
+ * We assume bus 0.
+ */
+#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
+#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
+static void								\
+mpc10x_##rw##_config_##size(unsigned int *cfg_addr, 			\
+		unsigned int *cfg_data, int devfn, int offset,		\
+		type val)						\
+{									\
+	out_be32(cfg_addr, 						\
+		 ((offset & 0xfc) << 24) | (devfn << 16)		\
+		 | (0 << 8) | 0x80);					\
+	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
+	return;    					 		\
+}
+
+MPC10X_PCI_OP(read, byte,  u8 *, in_8, 3)
+MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0)
+
+/*
+ * Read the memory controller registers to determine the amount of memory in
+ * the system.  This assumes that the firmware has correctly set up the memory
+ * controller registers.  On CONFIG_PPC_PREP, we know we are being called
+ * under a PReP memory map. On all other machines, we assume we are under
+ * a CHRP memory map.  Further, on CONFIG_PPC_MULTIPLATFORM we must rename
+ * this function.
+ */
+#ifdef CONFIG_PPC_MULTIPLATFORM
+#define get_mem_size mpc10x_get_mem_size
+#endif
+unsigned long
+get_mem_size(void)
+{
+	unsigned int *config_addr, *config_data, val;
+	unsigned long start, end, total, offset;
+	int i;
+	unsigned char bank_enables;
+
+#ifdef CONFIG_PPC_PREP
+	config_addr = (unsigned int *)MPC10X_MAPA_CNFG_ADDR;
+	config_data = (unsigned int *)MPC10X_MAPA_CNFG_DATA;
+#else
+	config_addr = (unsigned int *)MPC10X_MAPB_CNFG_ADDR;
+	config_data = (unsigned int *)MPC10X_MAPB_CNFG_DATA;
+#endif
+
+	mpc10x_read_config_byte(config_addr, config_data, PCI_DEVFN(0,0),
+			MPC10X_MCTLR_MEM_BANK_ENABLES, &bank_enables);
+
+	total = 0;
+
+	for (i = 0; i < 8; i++) {
+		if (bank_enables & (1 << i)) {
+			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			start = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			start = (val << 28) | (start << 20);
+
+			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			end = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			end = (val << 28) | (end << 20) | 0xfffff;
+
+			total += (end - start + 1);
+		}
+	}
+
+	return total;
+}
diff -Nru a/arch/ppc/boot/simple/relocate.S b/arch/ppc/boot/simple/relocate.S
--- a/arch/ppc/boot/simple/relocate.S	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/boot/simple/relocate.S	Sat Apr  3 19:38:43 2004
@@ -9,7 +9,7 @@
  *	   trini@mvista.com
  * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  *
- * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
+ * 2001-2004 (c) 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.
@@ -101,8 +101,8 @@
 	GETSYM(r4, __relocate_start)
 	GETSYM(r5, do_relocate)
 
-	sub	r4,r5,r4	/* Get entry point for do_relocate in
-	add	r6,r6,r4       * relocated section */
+	sub	r4,r5,r4	/* Get entry point for do_relocate in */
+	add	r6,r6,r4	/* relocated section */
 
 	/* This will return to the relocated do_relocate */
 	mtlr	r6
@@ -182,6 +182,7 @@
 	mr	r4,r7		/* Program length */
 	mr	r5,r6		/* Checksum */
 	mr	r6,r11		/* Residual data */
+	mr	r7,r25		/* Validated OFW interface */
 	bl	load_kernel
 
 	/*
@@ -195,8 +196,21 @@
 	/*
 	 * Start at the begining.
 	 */
-	li	r9,0x0000
+#ifdef CONFIG_PPC_MULTIPLATFORM
+	li	r9,0xc
 	mtlr	r9
+	/* tell kernel we're prep, by putting 0xdeadc0de at KERNELLOAD,
+	 * and tell the kernel to start on the 4th instruction since we
+	 * overwrite the first 3 sometimes (which are 'nop').
+	 */
+	lis	r10,0xdeadc0de@h
+	ori	r10,r10,0xdeadc0de@l
+	li	r9,0
+	stw	r10,0(r9)
+#else
+	li	r9,0
+	mtlr	r9
+#endif
 	blr
 
 	.comm	.stack,4096*2,4
diff -Nru a/arch/ppc/boot/utils/mkprep.c b/arch/ppc/boot/utils/mkprep.c
--- a/arch/ppc/boot/utils/mkprep.c	Sat Apr  3 19:38:45 2004
+++ b/arch/ppc/boot/utils/mkprep.c	Sat Apr  3 19:38:45 2004
@@ -219,6 +219,8 @@
   pe.number_of_sectors = cpu_to_le32(2*18*80-1);
 #endif /* __i386__ */
 
+  memcpy(&block[0x1BE], &pe, sizeof(pe));
+
   write( out, block, sizeof(block) );
   write( out, entry, sizeof(*entry) );
   write( out, length, sizeof(*length) );
diff -Nru a/arch/ppc/configs/ash_defconfig b/arch/ppc/configs/ash_defconfig
--- a/arch/ppc/configs/ash_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc/configs/ash_defconfig	Sat Apr  3 19:38:41 2004
@@ -400,7 +400,6 @@
 # CONFIG_ADVANTECH_WDT is not set
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_SCx200_WDT is not set
 # CONFIG_60XX_WDT is not set
diff -Nru a/arch/ppc/configs/cedar_defconfig b/arch/ppc/configs/cedar_defconfig
--- a/arch/ppc/configs/cedar_defconfig	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc/configs/cedar_defconfig	Sat Apr  3 19:38:54 2004
@@ -366,7 +366,6 @@
 # CONFIG_ADVANTECH_WDT is not set
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_SCx200_WDT is not set
 # CONFIG_60XX_WDT is not set
diff -Nru a/arch/ppc/configs/common_defconfig b/arch/ppc/configs/common_defconfig
--- a/arch/ppc/configs/common_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc/configs/common_defconfig	Sat Apr  3 19:38:42 2004
@@ -241,7 +241,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/ppc/configs/cpci405_defconfig b/arch/ppc/configs/cpci405_defconfig
--- a/arch/ppc/configs/cpci405_defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/configs/cpci405_defconfig	Sat Apr  3 19:38:55 2004
@@ -177,7 +177,6 @@
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/ppc/configs/ebony_defconfig b/arch/ppc/configs/ebony_defconfig
--- a/arch/ppc/configs/ebony_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc/configs/ebony_defconfig	Sat Apr  3 19:38:42 2004
@@ -6,6 +6,7 @@
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
 
 #
 # Code maturity level options
@@ -23,14 +24,16 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
+CONFIG_EMBEDDED=y
 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
@@ -62,9 +65,9 @@
 # CONFIG_OCOTEA is not set
 CONFIG_440GP=y
 CONFIG_440=y
-CONFIG_PIN_TLB=y
 CONFIG_BOOKE=y
 CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
 # CONFIG_PM is not set
 CONFIG_NOT_COHERENT_CACHE=y
 
@@ -88,12 +91,6 @@
 CONFIG_PCI_DOMAINS=y
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
 
 #
 # Advanced setup
@@ -110,8 +107,13 @@
 CONFIG_BOOT_LOAD=0x01000000
 
 #
+# Device Drivers
+#
+
+#
 # Generic Driver Options
 #
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -119,29 +121,29 @@
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # 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 is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
 CONFIG_LBD=y
 
 #
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
 # ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -152,11 +154,17 @@
 # CONFIG_SCSI is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
@@ -166,6 +174,10 @@
 # CONFIG_I2O is not set
 
 #
+# Macintosh device drivers
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -188,7 +200,6 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
@@ -217,7 +228,6 @@
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -291,6 +301,7 @@
 # CONFIG_TR is not set
 # CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # Wan interfaces
@@ -311,23 +322,18 @@
 # Bluetooth support
 #
 # CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
+# CONFIG_ISDN is not set
 
 #
-# Console display driver support
+# Telephony Support
 #
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -367,15 +373,9 @@
 # CONFIG_INPUT_MISC is not set
 
 #
-# Macintosh device drivers
-#
-
-#
 # Character devices
 #
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
+# CONFIG_VT is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -397,30 +397,8 @@
 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
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -447,6 +425,15 @@
 # CONFIG_RAW_DRIVER is not set
 
 #
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -457,6 +444,26 @@
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# 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 is not set
@@ -489,7 +496,6 @@
 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_HUGETLB_PAGE is not set
@@ -501,6 +507,7 @@
 # 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
@@ -517,12 +524,13 @@
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 # CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 # CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -537,15 +545,9 @@
 CONFIG_MSDOS_PARTITION=y
 
 #
-# Sound
+# Native Language Support
 #
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
+# CONFIG_NLS is not set
 
 #
 # Library routines
diff -Nru a/arch/ppc/configs/pmac_defconfig b/arch/ppc/configs/pmac_defconfig
--- a/arch/ppc/configs/pmac_defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/configs/pmac_defconfig	Sat Apr  3 19:38:55 2004
@@ -247,7 +247,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/ppc/configs/power3_defconfig b/arch/ppc/configs/power3_defconfig
--- a/arch/ppc/configs/power3_defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc/configs/power3_defconfig	Sat Apr  3 19:38:42 2004
@@ -177,7 +177,6 @@
 CONFIG_MD_RAID5=y
 # CONFIG_MD_MULTIPATH is not set
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_IOCTL_V4=y
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -622,13 +621,11 @@
 # 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_KEYWEST is not set
 # CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PHILIPSPAR is not set
 # CONFIG_I2C_PIIX4 is not set
 # CONFIG_I2C_PROSAVAGE is not set
 # CONFIG_I2C_SAVAGE4 is not set
@@ -636,7 +633,6 @@
 # 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
diff -Nru a/arch/ppc/configs/pplus_defconfig b/arch/ppc/configs/pplus_defconfig
--- a/arch/ppc/configs/pplus_defconfig	Sat Apr  3 19:38:44 2004
+++ b/arch/ppc/configs/pplus_defconfig	Sat Apr  3 19:38:44 2004
@@ -4,11 +4,17 @@
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
@@ -18,9 +24,16 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_EMBEDDED is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+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
@@ -33,24 +46,25 @@
 CONFIG_KMOD=y
 
 #
-# Platform support
+# Processor
 #
-CONFIG_PPC=y
-CONFIG_PPC32=y
 CONFIG_6xx=y
 # CONFIG_40x is not set
+# CONFIG_44x is not set
 # CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
+# CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_STD_MMU=y
 
 #
-# IBM 4xx options
+# Platform options
 #
-# CONFIG_8260 is not set
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_PPC_STD_MMU=y
 # CONFIG_PPC_MULTIPLATFORM is not set
 # CONFIG_APUS is not set
-# CONFIG_WILLOW_2 is not set
+# CONFIG_WILLOW is not set
 # CONFIG_PCORE is not set
 # CONFIG_POWERPMC250 is not set
 # CONFIG_EV64260 is not set
@@ -66,34 +80,29 @@
 # CONFIG_K2 is not set
 # CONFIG_PAL4 is not set
 # CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX6 is not set
+# CONFIG_TQM8260 is not set
+CONFIG_PPC_GEN550=y
+# CONFIG_PPCBUG_NVRAM is not set
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
-# CONFIG_ALTIVEC is not set
-# CONFIG_TAU is not set
-# CONFIG_CPU_FREQ is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="ip=on"
 
 #
-# General setup
+# Bus options
 #
-# CONFIG_HIGHMEM is not set
+CONFIG_GENERIC_ISA_DMA=y
 CONFIG_PCI=y
 CONFIG_PCI_DOMAINS=y
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_ELF=y
-CONFIG_KERNEL_ELF=y
-# CONFIG_BINFMT_MISC is not set
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-CONFIG_PPC601_SYNC_FIX=y
-# CONFIG_PPCBUG_NVRAM is not set
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="ip=on"
 
 #
 # Advanced setup
@@ -110,14 +119,26 @@
 CONFIG_BOOT_LOAD=0x00800000
 
 #
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+
+#
 # Memory Technology Devices (MTD)
 #
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -131,43 +152,41 @@
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_LBD is not set
 
 #
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
 CONFIG_BLK_DEV_IDE=y
 
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
-# CONFIG_BLK_DEV_HD is not set
 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=y
 CONFIG_BLK_DEV_IDESCSI=y
 # 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 is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
 
 #
 # SCSI support type (disk, tape, CD-ROM)
@@ -196,11 +215,9 @@
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -208,39 +225,36 @@
 # 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_INITIO is not set
+# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C7xx is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_NCR53C8XX is not set
-CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
-# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT 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 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_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
 # Fusion MPT device support
 #
 # CONFIG_FUSION is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
@@ -250,6 +264,10 @@
 # CONFIG_I2O is not set
 
 #
+# Macintosh device drivers
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -260,8 +278,6 @@
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 # CONFIG_NETLINK_DEV is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
 CONFIG_UNIX=y
 # CONFIG_NET_KEY is not set
 CONFIG_INET=y
@@ -282,6 +298,16 @@
 # 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=m
@@ -292,11 +318,13 @@
 # CONFIG_IP_NF_QUEUE is not set
 CONFIG_IP_NF_IPTABLES=m
 CONFIG_IP_NF_MATCH_LIMIT=m
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
 CONFIG_IP_NF_MATCH_MAC=m
 CONFIG_IP_NF_MATCH_PKTTYPE=m
 CONFIG_IP_NF_MATCH_MARK=m
 CONFIG_IP_NF_MATCH_MULTIPORT=m
 CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
 CONFIG_IP_NF_MATCH_ECN=m
 CONFIG_IP_NF_MATCH_DSCP=m
 CONFIG_IP_NF_MATCH_AH_ESP=m
@@ -306,15 +334,15 @@
 CONFIG_IP_NF_MATCH_HELPER=m
 CONFIG_IP_NF_MATCH_STATE=m
 CONFIG_IP_NF_MATCH_CONNTRACK=m
-CONFIG_IP_NF_MATCH_UNCLEAN=m
 CONFIG_IP_NF_MATCH_OWNER=m
 CONFIG_IP_NF_FILTER=m
 CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_MIRROR=m
 CONFIG_IP_NF_NAT=m
 CONFIG_IP_NF_NAT_NEEDED=y
 CONFIG_IP_NF_TARGET_MASQUERADE=m
 CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_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_FTP=m
@@ -324,10 +352,9 @@
 # CONFIG_IP_NF_TARGET_TCPMSS is not set
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
+# CONFIG_IP_NF_ARP_MANGLE is not set
 CONFIG_IP_NF_COMPAT_IPCHAINS=m
 # CONFIG_IP_NF_COMPAT_IPFWADM is not set
-# CONFIG_IPV6 is not set
-# CONFIG_XFRM_USER is not set
 
 #
 # SCTP Configuration (EXPERIMENTAL)
@@ -336,9 +363,9 @@
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE 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
@@ -366,13 +393,13 @@
 # CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
 
 #
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
+CONFIG_CRC32=y
 # CONFIG_OAKNET is not set
 # CONFIG_HAPPYMEAL is not set
 # CONFIG_SUNGEM is not set
@@ -381,13 +408,22 @@
 #
 # Tulip family network device support
 #
-# CONFIG_NET_TULIP is not set
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+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
 # 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=y
 # CONFIG_EEPRO100_PIO is not set
@@ -413,6 +449,7 @@
 # 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 is not set
 
@@ -431,8 +468,9 @@
 # CONFIG_NET_RADIO is not set
 
 #
-# Token Ring devices (depends on LLC=y)
+# Token Ring devices
 #
+# CONFIG_TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
@@ -453,19 +491,19 @@
 # CONFIG_IRDA is not set
 
 #
-# ISDN subsystem
+# Bluetooth support
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_BT is not set
 
 #
-# Graphics support
+# ISDN subsystem
 #
-# CONFIG_FB is not set
+# CONFIG_ISDN is not set
 
 #
-# Old CD-ROM drivers (not SCSI, not IDE)
+# Telephony Support
 #
-# CONFIG_CD_NO_IDESCSI is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -482,18 +520,16 @@
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
 # CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
 
 #
 # Input Device Drivers
 #
 
 #
-# Macintosh device drivers
-#
-
-#
 # Character devices
 #
+# CONFIG_VT is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
@@ -501,6 +537,7 @@
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
 #
@@ -509,26 +546,13 @@
 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 Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 
 #
 # Mice
 #
-CONFIG_BUSMOUSE=y
+# CONFIG_BUSMOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -554,7 +578,11 @@
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
 # CONFIG_RAW_DRIVER is not set
-# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
 
 #
 # Multimedia devices
@@ -567,6 +595,26 @@
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# 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
@@ -600,10 +648,11 @@
 # Pseudo filesystems
 #
 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_HUGETLB_PAGE is not set
 CONFIG_RAMFS=y
 
 #
@@ -628,6 +677,7 @@
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 # CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
@@ -638,7 +688,6 @@
 # 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
 
 #
@@ -648,31 +697,18 @@
 CONFIG_MSDOS_PARTITION=y
 
 #
-# Sound
+# Native Language Support
 #
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_NLS is not set
 
 #
 # Library routines
 #
-# CONFIG_CRC32 is not set
 
 #
 # Kernel hacking
 #
 # CONFIG_DEBUG_KERNEL is not set
-# CONFIG_KALLSYMS is not set
 # CONFIG_SERIAL_TEXT_DEBUG is not set
 
 #
diff -Nru a/arch/ppc/configs/rainier_defconfig b/arch/ppc/configs/rainier_defconfig
--- a/arch/ppc/configs/rainier_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc/configs/rainier_defconfig	Sat Apr  3 19:38:41 2004
@@ -436,7 +436,6 @@
 # CONFIG_ADVANTECH_WDT is not set
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
-# CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
 # CONFIG_SCx200_WDT is not set
 # CONFIG_60XX_WDT is not set
diff -Nru a/arch/ppc/configs/redwood5_defconfig b/arch/ppc/configs/redwood5_defconfig
--- a/arch/ppc/configs/redwood5_defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/configs/redwood5_defconfig	Sat Apr  3 19:38:55 2004
@@ -173,7 +173,6 @@
 #
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/ppc/configs/walnut_defconfig b/arch/ppc/configs/walnut_defconfig
--- a/arch/ppc/configs/walnut_defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/configs/walnut_defconfig	Sat Apr  3 19:38:55 2004
@@ -6,6 +6,7 @@
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
 
 #
 # Code maturity level options
@@ -23,6 +24,7 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 # CONFIG_KALLSYMS is not set
@@ -31,6 +33,7 @@
 CONFIG_IOSCHED_NOOP=y
 CONFIG_IOSCHED_AS=y
 CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 
 #
 # Loadable module support
@@ -59,24 +62,20 @@
 # IBM 4xx options
 #
 # CONFIG_ASH is not set
-# CONFIG_BEECH is not set
-# CONFIG_CEDAR is not set
 # CONFIG_CPCI405 is not set
 # CONFIG_EP405 is not set
 # CONFIG_OAK is not set
-# CONFIG_REDWOOD_4 is not set
 # CONFIG_REDWOOD_5 is not set
 # CONFIG_REDWOOD_6 is not set
 # CONFIG_SYCAMORE is not set
-# CONFIG_TIVO is not set
 CONFIG_WALNUT=y
 CONFIG_IBM405_ERR77=y
 CONFIG_IBM405_ERR51=y
 CONFIG_IBM_OCP=y
+CONFIG_PPC_OCP=y
 CONFIG_BIOS_FIXUP=y
 CONFIG_405GP=y
 CONFIG_IBM_OPENBIOS=y
-# CONFIG_405_DMA is not set
 # CONFIG_PM is not set
 CONFIG_UART0_TTYS0=y
 # CONFIG_UART0_TTYS1 is not set
@@ -101,12 +100,6 @@
 CONFIG_PCI_DOMAINS=y
 CONFIG_PCI_LEGACY_PROC=y
 # CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
 
 #
 # Advanced setup
@@ -123,6 +116,10 @@
 CONFIG_BOOT_LOAD=0x00400000
 
 #
+# Device Drivers
+#
+
+#
 # Generic Driver Options
 #
 
@@ -132,13 +129,18 @@
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # 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
@@ -146,17 +148,13 @@
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_LBD is not set
 
 #
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
 # ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
@@ -167,11 +165,17 @@
 # CONFIG_SCSI is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
 # Fusion MPT device support
 #
+# CONFIG_FUSION is not set
 
 #
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+# IEEE 1394 (FireWire) support
 #
 # CONFIG_IEEE1394 is not set
 
@@ -181,6 +185,10 @@
 # CONFIG_I2O is not set
 
 #
+# Macintosh device drivers
+#
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -203,7 +211,6 @@
 # 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=y
 # CONFIG_INET_AH is not set
 # CONFIG_INET_ESP is not set
@@ -216,7 +223,6 @@
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
@@ -302,6 +308,7 @@
 # CONFIG_TR is not set
 # CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # Wan interfaces
@@ -322,16 +329,18 @@
 # Bluetooth support
 #
 # CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
-# Graphics support
+# Telephony Support
 #
-# CONFIG_FB is not set
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -368,10 +377,6 @@
 # CONFIG_INPUT_MISC is not set
 
 #
-# Macintosh device drivers
-#
-
-#
 # Character devices
 #
 # CONFIG_VT is not set
@@ -391,53 +396,8 @@
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-# CONFIG_I2C_CHARDEV is not set
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-
-#
-# 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_I801 is not set
-CONFIG_I2C_IBM_IIC=y
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -464,6 +424,15 @@
 # CONFIG_RAW_DRIVER is not set
 
 #
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -474,6 +443,26 @@
 # CONFIG_DVB is not set
 
 #
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# 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
@@ -507,7 +496,6 @@
 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
@@ -519,6 +507,7 @@
 # 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
@@ -535,12 +524,13 @@
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 # CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
 CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 # CONFIG_EXPORTFS is not set
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -566,19 +556,13 @@
 # CONFIG_EFI_PARTITION is not set
 
 #
-# Sound
+# Native Language Support
 #
-# CONFIG_SOUND is not set
+# CONFIG_NLS is not set
 
 #
 # IBM 40x options
 #
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
 
 #
 # Library routines
diff -Nru a/arch/ppc/defconfig b/arch/ppc/defconfig
--- a/arch/ppc/defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/defconfig	Sat Apr  3 19:38:55 2004
@@ -248,7 +248,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
--- a/arch/ppc/kernel/align.c	Sat Apr  3 19:38:40 2004
+++ b/arch/ppc/kernel/align.c	Sat Apr  3 19:38:40 2004
@@ -262,8 +262,12 @@
 			return -EFAULT;	/* bad address */
 	}
 
-	if ((flags & F) && (regs->msr & MSR_FP))
-		giveup_fpu(current);
+	if (flags & F) {
+		preempt_disable();
+		if (regs->msr & MSR_FP)
+			giveup_fpu(current);
+		preempt_enable();
+	}
 	if (flags & M)
 		return 0;		/* too hard for now */
 
@@ -321,14 +325,18 @@
 	 * the kernel with -msoft-float so it doesn't use the
 	 * fp regs for copying 8-byte objects. */
 	case LD+F+S:
+		preempt_disable();
 		enable_kernel_fp();
 		cvt_fd(&data.f, &current->thread.fpr[reg], &current->thread.fpscr);
 		/* current->thread.fpr[reg] = data.f; */
+		preempt_enable();
 		break;
 	case ST+F+S:
+		preempt_disable();
 		enable_kernel_fp();
 		cvt_df(&current->thread.fpr[reg], &data.f, &current->thread.fpscr);
 		/* data.f = current->thread.fpr[reg]; */
+		preempt_enable();
 		break;
 	default:
 		printk("align: can't handle flags=%x\n", flags);
diff -Nru a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
--- a/arch/ppc/kernel/cputable.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/kernel/cputable.c	Sat Apr  3 19:38:43 2004
@@ -476,6 +476,20 @@
         32, 32,
         0, /*__setup_cpu_440 */
     },
+    { /* 440GX Rev. B */
+        0xf0000fff, 0x50000851, "440GX Rev. B",
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+        32, 32,
+        0, /*__setup_cpu_440 */
+    },
+    { /* 440GX Rev. B1 (2.1) */
+        0xf0000fff, 0x50000852, "440GX Rev. B1 (2.1)",
+        CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+        PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+        32, 32,
+        0, /*__setup_cpu_440 */
+    },
 #endif /* CONFIG_44x */
 #if !CLASSIC_PPC
     {	/* default match */
diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
--- a/arch/ppc/kernel/entry.S	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/kernel/entry.S	Sat Apr  3 19:38:55 2004
@@ -171,9 +171,10 @@
 	bl	do_show_syscall
 #endif /* SHOW_SYSCALLS */
 	rlwinm	r10,r1,0,0,18	/* current_thread_info() */
+	lwz	r11,TI_LOCAL_FLAGS(r10)
+	rlwinm	r11,r11,0,~_TIFL_FORCE_NOERROR
+	stw	r11,TI_LOCAL_FLAGS(r10)
 	lwz	r11,TI_FLAGS(r10)
-	rlwinm	r11,r11,0,~_TIF_FORCE_NOERROR
-	stw	r11,TI_FLAGS(r10)
 	andi.	r11,r11,_TIF_SYSCALL_TRACE
 	bne-	syscall_dotrace
 syscall_dotrace_cont:
@@ -196,8 +197,8 @@
 	cmpl	0,r3,r11
 	rlwinm	r12,r1,0,0,18	/* current_thread_info() */
 	blt+	30f
-	lwz	r11,TI_FLAGS(r12)
-	andi.	r11,r11,_TIF_FORCE_NOERROR
+	lwz	r11,TI_LOCAL_FLAGS(r12)
+	andi.	r11,r11,_TIFL_FORCE_NOERROR
 	bne	30f
 	neg	r3,r3
 	lwz	r10,_CCR(r1)	/* Set SO bit in CR */
@@ -414,6 +415,14 @@
 	stw	r0,TRAP(r1)		/* register set saved */
 	b	sys_clone
 
+	.globl	ppc_swapcontext
+ppc_swapcontext:
+	SAVE_NVGPRS(r1)
+	lwz	r0,TRAP(r1)
+	rlwinm	r0,r0,0,0,30		/* clear LSB to indicate full */
+	stw	r0,TRAP(r1)		/* register set saved */
+	b	sys_swapcontext
+
 /*
  * This routine switches between two different tasks.  The process
  * state of one is saved on its kernel stack.  Then the state
@@ -460,10 +469,19 @@
 	stw	r10,_CCR(r1)
 	stw	r1,KSP(r3)	/* Set old stack pointer */
 
+#ifdef CONFIG_SMP
+	/* We need a sync somewhere here to make sure that if the
+	 * previous task gets rescheduled on another CPU, it sees all
+	 * stores it has performed on this one.
+	 */
+	sync
+#endif /* CONFIG_SMP */
+
 	tophys(r0,r4)
 	CLR_TOP32(r0)
 	mtspr	SPRG3,r0	/* Update current THREAD phys addr */
 	lwz	r1,KSP(r4)	/* Load new stack pointer */
+
 	/* save the old current 'last' for return value */
 	mr	r3,r2
 	addi	r2,r4,-THREAD	/* Update current */
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/kernel/head.S	Sat Apr  3 19:38:43 2004
@@ -462,7 +462,7 @@
 	EXC_XFER_EE(0x600, AlignmentException)
 
 /* Program check exception */
-	EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_EE)
+	EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_STD)
 
 /* Floating-point unavailable */
 	. = 0x800
@@ -485,7 +485,7 @@
 	EXC_XFER_EE_LITE(0xc00, DoSyscall)
 
 /* Single step - not used on 601 */
-	EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_EE)
+	EXCEPTION(0xd00, SingleStep, SingleStepException, EXC_XFER_STD)
 	EXCEPTION(0xe00, Trap_0e, UnknownException, EXC_XFER_EE)
 
 /*
@@ -1436,11 +1436,8 @@
 	stw	r4, 0x4(r5)
 #endif
 	li	r4,0
-BEGIN_FTR_SECTION
-	dssall
-	sync
-END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
-3:	isync
+	isync
+3:
 #ifdef CONFIG_PPC64BRIDGE
 	slbie	r4
 #endif /* CONFIG_PPC64BRIDGE */
diff -Nru a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S
--- a/arch/ppc/kernel/head_44x.S	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc/kernel/head_44x.S	Sat Apr  3 19:38:42 2004
@@ -860,6 +860,7 @@
 	lis	r13, tlb_44x_index@ha
 	lwz	r14, tlb_44x_index@l(r13)
 	/* Load the TLB high watermark */
+	lis	r13, tlb_44x_hwater@ha
 	lwz	r11, tlb_44x_hwater@l(r13)
 
 	/* Increment, rollover, and store TLB index */
@@ -869,6 +870,7 @@
 	li	r14, 0
 7:
 	/* Store the next available TLB index */
+	lis	r13, tlb_44x_index@ha
 	stw	r14, tlb_44x_index@l(r13)
 
 	lwz	r13, 0(r12)			/* Get MS word of PTE */
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/kernel/misc.S	Sat Apr  3 19:38:55 2004
@@ -1108,17 +1108,7 @@
 	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
@@ -1373,7 +1363,7 @@
 	.long sys_clock_gettime
 	.long sys_clock_getres
 	.long sys_clock_nanosleep
-	.long sys_swapcontext
+	.long ppc_swapcontext
 	.long sys_tgkill	/* 250 */
 	.long sys_utimes
 	.long sys_statfs64
diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/kernel/pci.c	Sat Apr  3 19:38:43 2004
@@ -159,7 +159,6 @@
 		ppc_md.pcibios_fixup_resources(dev);
 }
 
-
 void
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 			struct resource *res)
@@ -1522,51 +1521,43 @@
 {
 	struct pci_controller *hose = (struct pci_controller *) dev->sysdata;
 	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-	unsigned long io_offset = 0;
-	int i, res_bit;
+	unsigned long size = vma->vm_end - vma->vm_start;
+	unsigned long base;
+	struct resource *res;
+	int i;
+	int ret = -EINVAL;
 
 	if (hose == 0)
 		return -EINVAL;		/* should never happen */
+	if (offset + size <= offset)
+		return -EINVAL;
 
-	/* If memory, add on the PCI bridge address offset */
 	if (mmap_state == pci_mmap_mem) {
+		/* PCI memory space */
+		base = hose->pci_mem_offset;
+		for (i = 0; i < 3; ++i) {
+			res = &hose->mem_resources[i];
+			if (res->flags == 0)
+				continue;
+			if (offset >= res->start - base
+			    && offset + size - 1 <= res->end - base) {
+				ret = 0;
+				break;
+			}
+		}
 		offset += hose->pci_mem_offset;
-		res_bit = IORESOURCE_MEM;
 	} else {
-		io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
-		offset += io_offset;
-		res_bit = IORESOURCE_IO;
-	}
-
-	/*
-	 * Check that the offset requested corresponds to one of the
-	 * resources of the device.
-	 */
-	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-		struct resource *rp = &dev->resource[i];
-		int flags = rp->flags;
-
-		/* treat ROM as memory (should be already) */
-		if (i == PCI_ROM_RESOURCE)
-			flags |= IORESOURCE_MEM;
-
-		/* Active and same type? */
-		if ((flags & res_bit) == 0)
-			continue;
-
-		/* In the range of this resource? */
-		if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
-			continue;
-
-		/* found it! construct the final physical address */
-		if (mmap_state == pci_mmap_io)
-			offset += hose->io_base_phys - io_offset;
-
-		vma->vm_pgoff = offset >> PAGE_SHIFT;
-		return 0;
+		/* PCI I/O space */
+		base = (unsigned long)hose->io_base_virt - isa_io_base;
+		res = &hose->io_resource;
+		if (offset >= res->start - base
+		    && offset + size - 1 <= res->end - base)
+			ret = 0;
+		offset += hose->io_base_phys;
 	}
 
-	return -EINVAL;
+	vma->vm_pgoff = offset >> PAGE_SHIFT;
+	return ret;
 }
 
 /*
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/kernel/ppc_ksyms.c	Sat Apr  3 19:38:55 2004
@@ -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,16 +187,11 @@
 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);
 
 EXPORT_SYMBOL(flush_instruction_cache);
 EXPORT_SYMBOL(giveup_fpu);
-EXPORT_SYMBOL(enable_kernel_fp);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_range);
 EXPORT_SYMBOL(flush_icache_user_range);
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/kernel/process.c	Sat Apr  3 19:38:43 2004
@@ -45,7 +45,6 @@
 #include <asm/prom.h>
 #include <asm/hardirq.h>
 
-int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
 extern unsigned long _get_SP(void);
 
 struct task_struct *last_task_used_math = NULL;
@@ -164,6 +163,8 @@
 void
 enable_kernel_altivec(void)
 {
+	WARN_ON(current_thread_info()->preempt_count == 0 && !irqs_disabled());
+
 #ifdef CONFIG_SMP
 	if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
 		giveup_altivec(current);
@@ -173,11 +174,14 @@
 	giveup_altivec(last_task_used_altivec);
 #endif /* __SMP __ */
 }
+EXPORT_SYMBOL(enable_kernel_altivec);
 #endif /* CONFIG_ALTIVEC */
 
 void
 enable_kernel_fp(void)
 {
+	WARN_ON(current_thread_info()->preempt_count == 0 && !irqs_disabled());
+
 #ifdef CONFIG_SMP
 	if (current->thread.regs && (current->thread.regs->msr & MSR_FP))
 		giveup_fpu(current);
@@ -187,13 +191,16 @@
 	giveup_fpu(last_task_used_math);
 #endif /* CONFIG_SMP */
 }
+EXPORT_SYMBOL(enable_kernel_fp);
 
 int
-dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
+dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
 {
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	memcpy(fpregs, &current->thread.fpr[0], sizeof(*fpregs));
+	preempt_disable();
+	if (tsk->thread.regs && (tsk->thread.regs->msr & MSR_FP))
+		giveup_fpu(tsk);
+	preempt_enable();
+	memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs));
 	return 1;
 }
 
@@ -330,12 +337,14 @@
 
 	if (regs == NULL)
 		return;
+	preempt_disable();
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 #ifdef CONFIG_ALTIVEC
 	if (regs->msr & MSR_VEC)
 		giveup_altivec(current);
 #endif /* CONFIG_ALTIVEC */
+	preempt_enable();
 }
 
 /*
@@ -480,12 +489,14 @@
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
+	preempt_disable();
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 #ifdef CONFIG_ALTIVEC
 	if (regs->msr & MSR_VEC)
 		giveup_altivec(current);
 #endif /* CONFIG_ALTIVEC */
+	preempt_enable();
 	error = do_execve(filename, (char __user *__user *) a1,
 			  (char __user *__user *) a2, regs);
 	if (error == 0)
diff -Nru a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
--- a/arch/ppc/kernel/ptrace.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc/kernel/ptrace.c	Sat Apr  3 19:38:42 2004
@@ -242,8 +242,10 @@
 		if (index < PT_FPR0) {
 			tmp = get_reg(child, (int) index);
 		} else {
+			preempt_disable();
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
+			preempt_enable();
 			tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
 		}
 		ret = put_user(tmp,(unsigned long *) data);
@@ -276,8 +278,10 @@
 		if (index < PT_FPR0) {
 			ret = put_reg(child, index, data);
 		} else {
+			preempt_disable();
 			if (child->thread.regs->msr & MSR_FP)
 				giveup_fpu(child);
+			preempt_enable();
 			((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
 			ret = 0;
 		}
@@ -338,8 +342,10 @@
 #ifdef CONFIG_ALTIVEC
 	case PTRACE_GETVRREGS:
 		/* Get the child altivec register state. */
+		preempt_disable();
 		if (child->thread.regs->msr & MSR_VEC)
 			giveup_altivec(child);
+		preempt_enable();
 		ret = get_vrregs((unsigned long *)data, child);
 		break;
 
@@ -347,8 +353,10 @@
 		/* Set the child altivec register state. */
 		/* this is to clear the MSR_VEC bit to force a reload
 		 * of register state from memory */
+		preempt_disable();
 		if (child->thread.regs->msr & MSR_VEC)
 			giveup_altivec(child);
+		preempt_enable();
 		ret = set_vrregs(child, (unsigned long *)data);
 		break;
 #endif
diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
--- a/arch/ppc/kernel/signal.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc/kernel/signal.c	Sat Apr  3 19:38:56 2004
@@ -191,8 +191,15 @@
 {
 	/* save general and floating-point registers */
 	CHECK_FULL_REGS(regs);
+	preempt_disable();
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
+#ifdef CONFIG_ALTIVEC
+	if (current->thread.used_vr && (regs->msr & MSR_VEC))
+		giveup_altivec(current);
+#endif /* CONFIG_ALTIVEC */
+	preempt_enable();
+
 	if (__copy_to_user(&frame->mc_gregs, regs, GP_REGS_SIZE)
 	    || __copy_to_user(&frame->mc_fregs, current->thread.fpr,
 			      ELF_NFPREG * sizeof(double)))
@@ -203,8 +210,6 @@
 #ifdef CONFIG_ALTIVEC
 	/* save altivec registers */
 	if (current->thread.used_vr) {
-		if (regs->msr & MSR_VEC)
-			giveup_altivec(current);
 		if (__copy_to_user(&frame->mc_vregs, current->thread.vr,
 				   ELF_NVRREG * sizeof(vector128)))
 			return 1;
diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
--- a/arch/ppc/kernel/smp.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/kernel/smp.c	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
--- a/arch/ppc/kernel/traps.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc/kernel/traps.c	Sat Apr  3 19:38:41 2004
@@ -79,6 +79,7 @@
 void die(const char * str, struct pt_regs * fp, long err)
 {
 	static int die_counter;
+	int nl = 0;
 	console_verbose();
 	spin_lock_irq(&die_lock);
 #ifdef CONFIG_PMAC_BACKLIGHT
@@ -86,6 +87,16 @@
 	set_backlight_level(BACKLIGHT_MAX);
 #endif
 	printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
+#ifdef CONFIG_PREEMPT
+	printk("PREEMPT ");
+	nl = 1;
+#endif
+#ifdef CONFIG_SMP
+	printk("SMP NR_CPUS=%d ", NR_CPUS);
+	nl = 1;
+#endif
+	if (nl)
+		printk("\n");
 	show_regs(fp);
 	spin_unlock_irq(&die_lock);
 	/* do_exit() should take care of panic'ing from an interrupt
@@ -380,14 +391,25 @@
 		return 0;
 	if (bug->line & BUG_WARNING_TRAP) {
 		/* this is a WARN_ON rather than BUG/BUG_ON */
+#ifdef CONFIG_XMON
+		xmon_printf(KERN_ERR "Badness in %s at %s:%d\n",
+		       bug->function, bug->file,
+		       bug->line & ~BUG_WARNING_TRAP);
+#endif /* CONFIG_XMON */		
 		printk(KERN_ERR "Badness in %s at %s:%d\n",
 		       bug->function, bug->file,
 		       bug->line & ~BUG_WARNING_TRAP);
 		dump_stack();
 		return 1;
 	}
+#ifdef CONFIG_XMON
+	xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%d!\n",
+	       bug->function, bug->file, bug->line);
+	xmon(regs);
+#endif /* CONFIG_XMON */
 	printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n",
 	       bug->function, bug->file, bug->line);
+
 	return 0;
 }
 
@@ -416,8 +438,14 @@
 		int code = 0;
 		u32 fpscr;
 
+		/* We must make sure the FP state is consistent with
+		 * our MSR_FP in regs
+		 */
+		preempt_disable();
 		if (regs->msr & MSR_FP)
 			giveup_fpu(current);
+		preempt_enable();
+
 		fpscr = current->thread.fpscr;
 		fpscr &= fpscr << 22;	/* mask summary bits with enables */
 		if (fpscr & FPSCR_VX)
@@ -581,12 +609,16 @@
 void
 AltivecAssistException(struct pt_regs *regs)
 {
+	preempt_disable();
 	if (regs->msr & MSR_VEC)
 		giveup_altivec(current);
+	preempt_enable();
+
 	/* XXX quick hack for now: set the non-Java bit in the VSCR */
 	current->thread.vscr.u[3] |= 0x10000;
 }
 #endif /* CONFIG_ALTIVEC */
+
 
 void __init trap_init(void)
 {
diff -Nru a/arch/ppc/mm/cachemap.c b/arch/ppc/mm/cachemap.c
--- a/arch/ppc/mm/cachemap.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc/mm/cachemap.c	Sat Apr  3 19:38:56 2004
@@ -35,7 +35,7 @@
 #include <linux/delay.h>
 #include <linux/bootmem.h>
 #include <linux/highmem.h>
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
@@ -143,15 +143,15 @@
 	unsigned long end   = start + size;
 
 	switch (direction) {
-	case PCI_DMA_NONE:
+	case DMA_NONE:
 		BUG();
-	case PCI_DMA_FROMDEVICE:	/* invalidate only */
+	case DMA_FROM_DEVICE:	/* invalidate only */
 		invalidate_dcache_range(start, end);
 		break;
-	case PCI_DMA_TODEVICE:		/* writeback only */
+	case DMA_TO_DEVICE:		/* writeback only */
 		clean_dcache_range(start, end);
 		break;
-	case PCI_DMA_BIDIRECTIONAL:	/* writeback and invalidate */
+	case DMA_BIDIRECTIONAL:	/* writeback and invalidate */
 		flush_dcache_range(start, end);
 		break;
 	}
diff -Nru a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
--- a/arch/ppc/mm/pgtable.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc/mm/pgtable.c	Sat Apr  3 19:38:41 2004
@@ -143,7 +143,7 @@
 void *
 ioremap(phys_addr_t addr, unsigned long size)
 {
-	phys_addr_t addr64 = fixup_bigphys_addr(addr, size);;
+	phys_addr_t addr64 = fixup_bigphys_addr(addr, size);
 
 	return ioremap64(addr64, size);
 }
diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
--- a/arch/ppc/platforms/Makefile	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc/platforms/Makefile	Sat Apr  3 19:38:56 2004
@@ -41,11 +41,11 @@
 obj-$(CONFIG_PAL4)		+= pal4_setup.o pal4_pci.o
 obj-$(CONFIG_PCORE)		+= pcore_setup.o pcore_pci.o
 obj-$(CONFIG_POWERPMC250)	+= powerpmc250.o
-obj-$(CONFIG_PPLUS)		+= pplus_pci.o pplus_setup.o
+obj-$(CONFIG_PPLUS)		+= pplus.o
 obj-$(CONFIG_PRPMC750)		+= prpmc750_setup.o prpmc750_pci.o
 obj-$(CONFIG_PRPMC800)		+= prpmc800_setup.o prpmc800_pci.o
 obj-$(CONFIG_SANDPOINT)		+= sandpoint.o
-obj-$(CONFIG_SPRUCE)		+= spruce_setup.o spruce_pci.o
+obj-$(CONFIG_SPRUCE)		+= spruce.o
 
 ifeq ($(CONFIG_SMP),y)
 obj-$(CONFIG_PPC_PMAC)		+= pmac_smp.o
diff -Nru a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c
--- a/arch/ppc/platforms/chrp_smp.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc/platforms/chrp_smp.c	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
--- a/arch/ppc/platforms/pmac_feature.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/platforms/pmac_feature.c	Sat Apr  3 19:38:55 2004
@@ -1360,7 +1360,7 @@
 		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 -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
--- a/arch/ppc/platforms/pmac_smp.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/platforms/pmac_smp.c	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/arch/ppc/platforms/pplus.c b/arch/ppc/platforms/pplus.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/pplus.c	Sat Apr  3 19:38:56 2004
@@ -0,0 +1,918 @@
+/*
+ * arch/ppc/platforms/pplus.c
+ *
+ * Board and PCI setup routines for MCG PowerPlus
+ *
+ * Author: Randy Vinson <rvinson@mvista.com>
+ *
+ * Derived from original PowerPlus PReP work by
+ * Cort Dougan, Johnnie Peters, Matt Porter, and
+ * Troy Benjegerdes.
+ *
+ * 2001-2004 (c) 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.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/console.h>
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/vga.h>
+#include <asm/i8259.h>
+#include <asm/open_pic.h>
+#include <asm/hawk.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/kgdb.h>
+#include <asm/reg.h>
+
+#include "pplus.h"
+
+#undef DUMP_DBATS
+
+TODC_ALLOC();
+
+extern char saved_command_line[];
+
+extern void pplus_setup_hose(void);
+extern void pplus_set_VIA_IDE_native(void);
+
+extern unsigned long loops_per_jiffy;
+unsigned char *Motherboard_map_name;
+
+/* Tables for known hardware */
+
+/* Motorola Mesquite */
+static inline int
+mesquite_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+	     *      Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *         A   B   C   D
+	     */
+	{
+		{18,  0,  0,  0},	/* IDSEL 14 - Enet 0 */
+		{ 0,  0,  0,  0},	/* IDSEL 15 - unused */
+		{19, 19, 19, 19},	/* IDSEL 16 - PMC Slot 1 */
+		{ 0,  0,  0,  0},	/* IDSEL 17 - unused */
+		{ 0,  0,  0,  0},	/* IDSEL 18 - unused */
+		{ 0,  0,  0,  0},	/* IDSEL 19 - unused */
+		{24, 25, 26, 27},	/* IDSEL 20 - P2P bridge (to cPCI 1) */
+		{ 0,  0,  0,  0},	/* IDSEL 21 - unused */
+		{28, 29, 30, 31}	/* IDSEL 22 - P2P bridge (to cPCI 2) */
+	};
+
+	const long min_idsel = 14, max_idsel = 22, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+/* Motorola Sitka */
+static inline int
+sitka_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+	     *      Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *         A   B   C   D
+	     */
+	{
+		{18,  0,  0,  0},	/* IDSEL 14 - Enet 0 */
+		{ 0,  0,  0,  0},	/* IDSEL 15 - unused */
+		{25, 26, 27, 28},	/* IDSEL 16 - PMC Slot 1 */
+		{28, 25, 26, 27},	/* IDSEL 17 - PMC Slot 2 */
+		{ 0,  0,  0,  0},	/* IDSEL 18 - unused */
+		{ 0,  0,  0,  0},	/* IDSEL 19 - unused */
+		{20,  0,  0,  0}	/* IDSEL 20 - P2P bridge (to cPCI) */
+	};
+
+	const long min_idsel = 14, max_idsel = 20, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+/* Motorola MTX */
+static inline int
+MTX_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+	     *      Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *         A   B   C   D
+	     */
+	{
+		{19,  0,  0,  0},	/* IDSEL 12 - SCSI   */
+		{ 0,  0,  0,  0},	/* IDSEL 13 - unused */
+		{18,  0,  0,  0},	/* IDSEL 14 - Enet   */
+		{ 0,  0,  0,  0},	/* IDSEL 15 - unused */
+		{25, 26, 27, 28},	/* IDSEL 16 - PMC Slot 1 */
+		{26, 27, 28, 25},	/* IDSEL 17 - PMC Slot 2 */
+		{27, 28, 25, 26}	/* IDSEL 18 - PCI Slot 3 */
+	};
+
+	const long min_idsel = 12, max_idsel = 18, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+/* Motorola MTX Plus */
+/* Secondary bus interrupt routing is not supported yet */
+static inline int
+MTXplus_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+	    /*
+	     *      MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+	     *      Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *         A   B   C   D
+	     */
+	{
+		{19,  0,  0,  0},	/* IDSEL 12 - SCSI   */
+		{ 0,  0,  0,  0},	/* IDSEL 13 - unused */
+		{18,  0,  0,  0},	/* IDSEL 14 - Enet 1 */
+		{ 0,  0,  0,  0},	/* IDSEL 15 - unused */
+		{25, 26, 27, 28},	/* IDSEL 16 - PCI Slot 1P */
+		{26, 27, 28, 25},	/* IDSEL 17 - PCI Slot 2P */
+		{27, 28, 25, 26},	/* IDSEL 18 - PCI Slot 3P */
+		{26,  0,  0,  0},	/* IDSEL 19 - Enet 2 */
+		{ 0,  0,  0,  0}	/* IDSEL 20 - P2P Bridge */
+	};
+
+	const long min_idsel = 12, max_idsel = 20, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static inline int
+Genesis2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	/* 2600
+	 * Raven 31
+	 * ISA   11
+	 * SCSI  12 - IRQ3
+	 * Univ  13
+	 * eth   14 - IRQ2
+	 * VGA   15 - IRQ4
+	 * PMC1  16 - IRQ9,10,11,12 = PMC1 A-D
+	 * PMC2  17 - IRQ12,9,10,11 = A-D
+	 * SCSI2 18 - IRQ11
+	 * eth2  19 - IRQ10
+	 * PCIX  20 - IRQ9,10,11,12 = PCI A-D
+	 */
+
+	/* 2400
+	 * Hawk 31
+	 * ISA  11
+	 * Univ 13
+	 * eth  14 - IRQ2
+	 * PMC1 16 - IRQ9,10,11,12 = PMC A-D
+	 * PMC2 17 - IRQ12,9,10,11 = PMC A-D
+	 * PCIX 20 - IRQ9,10,11,12 = PMC A-D
+	 */
+
+	/* 2300
+	 * Raven 31
+	 * ISA   11
+	 * Univ  13
+	 * eth   14 - IRQ2
+	 * PMC1  16 - 9,10,11,12 = A-D
+	 * PMC2  17 - 9,10,11,12 = B,C,D,A
+	 */
+
+	static char pci_irq_table[][4] =
+	    /*
+	     *      MPIC interrupts for various IDSEL values (MPIC IRQ0 =
+	     *      Linux IRQ16 (to leave room for ISA IRQs at 0-15).
+	     *      PCI IDSEL/INTPIN->INTLINE
+	     *         A   B   C   D
+	     */
+	{
+		{19,  0,  0,  0},	/* IDSEL 12 - SCSI   */
+		{ 0,  0,  0,  0},	/* IDSEL 13 - Universe PCI - VME */
+		{18,  0,  0,  0},	/* IDSEL 14 - Enet 1 */
+		{ 0,  0,  0,  0},	/* IDSEL 15 - unused */
+		{25, 26, 27, 28},	/* IDSEL 16 - PCI/PMC Slot 1P */
+		{28, 25, 26, 27},	/* IDSEL 17 - PCI/PMC Slot 2P */
+		{27, 28, 25, 26},	/* IDSEL 18 - PCI Slot 3P */
+		{26,  0,  0,  0},	/* IDSEL 19 - Enet 2 */
+		{25, 26, 27, 28}	/* IDSEL 20 - P2P Bridge */
+	};
+
+	const long min_idsel = 12, max_idsel = 20, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+#define MOTOROLA_CPUTYPE_REG	0x800
+#define MOTOROLA_BASETYPE_REG	0x803
+#define MPIC_RAVEN_ID		0x48010000
+#define	MPIC_HAWK_ID		0x48030000
+#define	MOT_PROC2_BIT		0x800
+
+static u_char pplus_openpic_initsenses[] __initdata = {
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */
+	(IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_FALCN_ECC_ERR */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_PCI_ETHERNET */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),/*MVME2600_INT_PCI_GRAPHICS */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME2 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_VME3 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTA */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTB */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTC */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_INTD */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG0 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_LM_SIG1 */
+	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),
+};
+
+int mot_entry = -1;
+int prep_keybd_present = 1;
+int mot_multi = 0;
+
+struct brd_info {
+	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge
+	 * are set */
+	int cpu_type;
+	/* 0x200 if this board has a Hawk chip. */
+	int base_type;
+	/* or'ed with 0x80 if this board should be checked for multi CPU */
+	int max_cpu;
+	const char *name;
+	int (*map_irq) (struct pci_dev *, unsigned char, unsigned char);
+};
+struct brd_info mot_info[] = {
+	{0x300, 0x00, 0x00, "MVME 2400", Genesis2_map_irq},
+	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", mesquite_map_irq},
+	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", sitka_map_irq},
+	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", mesquite_map_irq},
+	{0x1E0, 0xF6, 0x80, "MTX Plus", MTXplus_map_irq},
+	{0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_map_irq},
+	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_map_irq},
+	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_map_irq},
+	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_map_irq},
+	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_map_irq},
+	{0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_map_irq},
+	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600", Genesis2_map_irq},
+	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_map_irq},
+	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_map_irq},
+	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_map_irq},
+	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_map_irq},
+	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_map_irq},
+	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_map_irq},
+	{0x000, 0x00, 0x00, "", NULL}
+};
+
+void __init pplus_set_board_type(void)
+{
+	unsigned char cpu_type;
+	unsigned char base_mod;
+	int entry;
+	unsigned short devid;
+	unsigned long *ProcInfo = NULL;
+
+	cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
+	base_mod = inb(MOTOROLA_BASETYPE_REG);
+	early_read_config_word(0, 0, 0, PCI_VENDOR_ID, &devid);
+
+	for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
+		/* Check for Hawk chip */
+		if (mot_info[entry].cpu_type & 0x200) {
+			if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK)
+				continue;
+		} else {
+			/* store the system config register for later use. */
+			ProcInfo =
+			    (unsigned long *)ioremap(PPLUS_SYS_CONFIG_REG, 4);
+
+			/* Check non hawk boards */
+			if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
+				continue;
+
+			if (mot_info[entry].base_type == 0) {
+				mot_entry = entry;
+				break;
+			}
+
+			if (mot_info[entry].base_type != base_mod)
+				continue;
+		}
+
+		if (!(mot_info[entry].max_cpu & 0x80)) {
+			mot_entry = entry;
+			break;
+		}
+
+		/* processor 1 not present and max processor zero indicated */
+		if ((*ProcInfo & MOT_PROC2_BIT)
+		    && !(mot_info[entry].max_cpu & 0x7f)) {
+			mot_entry = entry;
+			break;
+		}
+
+		/* processor 1 present and max processor zero indicated */
+		if (!(*ProcInfo & MOT_PROC2_BIT)
+		    && (mot_info[entry].max_cpu & 0x7f)) {
+			mot_entry = entry;
+			break;
+		}
+
+		/* Indicate to system if this is a multiprocessor board */
+		if (!(*ProcInfo & MOT_PROC2_BIT))
+			mot_multi = 1;
+	}
+
+	if (mot_entry == -1)
+		/* No particular cpu type found - assume Mesquite (MCP750) */
+		mot_entry = 1;
+
+	Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
+	ppc_md.pci_map_irq = mot_info[mot_entry].map_irq;
+}
+void __init pplus_pib_init(void)
+{
+	unsigned char reg;
+	unsigned short short_reg;
+
+	struct pci_dev *dev = NULL;
+
+	/*
+	 * Perform specific configuration for the Via Tech or
+	 * or Winbond PCI-ISA-Bridge part.
+	 */
+	if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+				   PCI_DEVICE_ID_VIA_82C586_1, dev))) {
+		/*
+		 * PPCBUG does not set the enable bits
+		 * for the IDE device. Force them on here.
+		 */
+		pci_read_config_byte(dev, 0x40, &reg);
+
+		reg |= 0x03;	/* IDE: Chip Enable Bits */
+		pci_write_config_byte(dev, 0x40, reg);
+	}
+
+	if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+				   PCI_DEVICE_ID_VIA_82C586_2,
+				   dev)) && (dev->devfn = 0x5a)) {
+		/* Force correct USB interrupt */
+		dev->irq = 11;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+
+	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+				   PCI_DEVICE_ID_WINBOND_83C553, dev))) {
+		/* Clear PCI Interrupt Routing Control Register. */
+		short_reg = 0x0000;
+		pci_write_config_word(dev, 0x44, short_reg);
+		/* Route IDE interrupts to IRQ 14 */
+		reg = 0xEE;
+		pci_write_config_byte(dev, 0x43, reg);
+	}
+
+	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
+				   PCI_DEVICE_ID_WINBOND_82C105, dev))) {
+		/*
+		 * Disable LEGIRQ mode so PCI INTS are routed
+		 * directly to the 8259 and enable both channels
+		 */
+		pci_write_config_dword(dev, 0x40, 0x10ff0033);
+
+		/* Force correct IDE interrupt */
+		dev->irq = 14;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+}
+
+void __init pplus_set_VIA_IDE_legacy(void)
+{
+	unsigned short vend, dev;
+
+	early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
+	early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
+
+	if ((vend == PCI_VENDOR_ID_VIA) &&
+			(dev == PCI_DEVICE_ID_VIA_82C586_1)) {
+		unsigned char temp;
+
+		/* put back original "standard" port base addresses */
+		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+					 PCI_BASE_ADDRESS_0, 0x1f1);
+		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+					 PCI_BASE_ADDRESS_1, 0x3f5);
+		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+					 PCI_BASE_ADDRESS_2, 0x171);
+		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+					 PCI_BASE_ADDRESS_3, 0x375);
+		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
+					 PCI_BASE_ADDRESS_4, 0xcc01);
+
+		/* put into legacy mode */
+		early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+				       &temp);
+		temp &= ~0x05;
+		early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+					temp);
+	}
+}
+
+void pplus_set_VIA_IDE_native(void)
+{
+	unsigned short vend, dev;
+
+	early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
+	early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
+
+	if ((vend == PCI_VENDOR_ID_VIA) &&
+			(dev == PCI_DEVICE_ID_VIA_82C586_1)) {
+		unsigned char temp;
+
+		/* put into native mode */
+		early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+				       &temp);
+		temp |= 0x05;
+		early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
+					temp);
+	}
+}
+
+void __init pplus_pcibios_fixup(void)
+{
+
+	unsigned char reg;
+	unsigned short devid;
+	unsigned char base_mod;
+
+	printk(KERN_INFO "Setting PCI interrupts for a \"%s\"\n",
+			Motherboard_map_name);
+
+	/* Setup the Winbond or Via PIB */
+	pplus_pib_init();
+
+	/* Set up floppy in PS/2 mode */
+	outb(0x09, SIO_CONFIG_RA);
+	reg = inb(SIO_CONFIG_RD);
+	reg = (reg & 0x3F) | 0x40;
+	outb(reg, SIO_CONFIG_RD);
+	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
+
+	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
+	 * no keyboard controller and we have to indicate that.
+	 */
+
+	early_read_config_word(0, 0, 0, PCI_VENDOR_ID, &devid);
+	base_mod = inb(MOTOROLA_BASETYPE_REG);
+	if ((devid == PCI_DEVICE_ID_MOTOROLA_HAWK) ||
+	    (base_mod == 0xF9) || (base_mod == 0xFA) || (base_mod == 0xE1))
+		prep_keybd_present = 0;
+}
+
+void __init pplus_find_bridges(void)
+{
+	struct pci_controller *hose;
+
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
+	hose->io_base_virt = (void *)PREP_ISA_IO_BASE;
+
+	pci_init_resource(&hose->io_resource, PPLUS_PCI_IO_START,
+			  PPLUS_PCI_IO_END, IORESOURCE_IO, "PCI host bridge");
+	pci_init_resource(&hose->mem_resources[0], PPLUS_PROC_PCI_MEM_START,
+			  PPLUS_PROC_PCI_MEM_END, IORESOURCE_MEM,
+			  "PCI host bridge");
+
+	hose->io_space.start = PPLUS_PCI_IO_START;
+	hose->io_space.end = PPLUS_PCI_IO_END;
+	hose->mem_space.start = PPLUS_PCI_MEM_START;
+	hose->mem_space.end = PPLUS_PCI_MEM_END - HAWK_MPIC_SIZE;
+
+	if (pplus_init(hose, PPLUS_HAWK_PPC_REG_BASE, PPLUS_PROC_PCI_MEM_START,
+				PPLUS_PROC_PCI_MEM_END - HAWK_MPIC_SIZE,
+				PPLUS_PROC_PCI_IO_START, PPLUS_PROC_PCI_IO_END,
+				PPLUS_PROC_PCI_MEM_END - HAWK_MPIC_SIZE + 1)
+			!= 0) {
+		printk(KERN_CRIT "Could not initialize host bridge\n");
+
+	}
+
+	pplus_set_VIA_IDE_legacy();
+
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pcibios_fixup = pplus_pcibios_fixup;
+	ppc_md.pci_swizzle = common_swizzle;
+}
+
+static int pplus_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "vendor\t\t: Motorola MCG\n");
+	seq_printf(m, "machine\t\t: %s\n", Motherboard_map_name);
+
+	return 0;
+}
+
+static void __init pplus_setup_arch(void)
+{
+	struct pci_controller *hose;
+
+	if (ppc_md.progress)
+		ppc_md.progress("pplus_setup_arch: enter", 0);
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000;
+
+	if (ppc_md.progress)
+		ppc_md.progress("pplus_setup_arch: find_bridges", 0);
+
+	/* Setup PCI host bridge */
+	pplus_find_bridges();
+
+	hose = pci_bus_to_hose(0);
+	isa_io_base = (ulong) hose->io_base_virt;
+
+	if (ppc_md.progress)
+		ppc_md.progress("pplus_setup_arch: set_board_type", 0);
+
+	pplus_set_board_type();
+
+	/* Enable L2.  Assume we don't need to flush -- Cort */
+	*(unsigned char *)(PPLUS_L2_CONTROL_REG) |= 3;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
+#endif
+#ifdef CONFIG_ROOT_NFS
+		ROOT_DEV = Root_NFS;
+#else
+		ROOT_DEV = Root_SDA2;
+#endif
+
+	printk(KERN_INFO "Motorola PowerPlus Platform\n");
+	printk(KERN_INFO
+	       "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+
+#ifdef CONFIG_VGA_CONSOLE
+	/* remap the VGA memory */
+	vgacon_remap_base = (unsigned long)ioremap(PPLUS_ISA_MEM_BASE,
+						   0x08000000);
+	conswitchp = &vga_con;
+#elif defined(CONFIG_DUMMY_CONSOLE)
+	conswitchp = &dummy_con;
+#endif
+#ifdef CONFIG_PPCBUG_NVRAM
+	/* Read in NVRAM data */
+	init_prep_nvram();
+
+	/* if no bootargs, look in NVRAM */
+	if (cmd_line[0] == '\0') {
+		char *bootargs;
+		bootargs = prep_nvram_get_var("bootargs");
+		if (bootargs != NULL) {
+			strcpy(cmd_line, bootargs);
+			/* again.. */
+			strcpy(saved_command_line, cmd_line);
+		}
+	}
+#endif
+	if (ppc_md.progress)
+		ppc_md.progress("pplus_setup_arch: exit", 0);
+}
+
+static void pplus_restart(char *cmd)
+{
+	unsigned long i = 10000;
+
+	local_irq_disable();
+
+	/* set VIA IDE controller into native mode */
+	pplus_set_VIA_IDE_native();
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb(inb(0x92) & ~1L, 0x92);
+	/* signal a reset to system control port A - soft reset */
+	outb(inb(0x92) | 1, 0x92);
+
+	while (i != 0)
+		i++;
+	panic("restart failed\n");
+}
+
+static void pplus_halt(void)
+{
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(MSR_EE, MSR_IP);
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb(inb(0x92) & ~1L, 0x92);
+	/* signal a reset to system control port A - soft reset */
+	outb(inb(0x92) | 1, 0x92);
+
+	while (1) ;
+	/*
+	 * Not reached
+	 */
+}
+
+static void pplus_power_off(void)
+{
+	pplus_halt();
+}
+
+static unsigned int pplus_irq_canonicalize(u_int irq)
+{
+	if (irq == 2)
+		return 9;
+	else
+		return irq;
+}
+
+static void __init pplus_init_IRQ(void)
+{
+	int i;
+
+	if (ppc_md.progress)
+		ppc_md.progress("init_irq: enter", 0);
+
+	OpenPIC_InitSenses = pplus_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(pplus_openpic_initsenses);
+
+	if (OpenPIC_Addr != NULL) {
+
+		openpic_set_sources(0, 16, OpenPIC_Addr + 0x10000);
+		openpic_init(NUM_8259_INTERRUPTS);
+		ppc_md.get_irq = openpic_get_irq;
+	}
+
+	for (i = 0; i < NUM_8259_INTERRUPTS; i++)
+		irq_desc[i].handler = &i8259_pic;
+
+	i8259_init(0);
+
+	if (ppc_md.progress)
+		ppc_md.progress("init_irq: exit", 0);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+static int pplus_ide_default_irq(unsigned long base)
+{
+	switch (base) {
+	case 0x1f0:
+		return 14;
+	case 0x170:
+		return 15;
+	default:
+		return 0;
+	}
+}
+
+static unsigned long pplus_ide_default_io_base(int index)
+{
+	switch (index) {
+	case 0:
+		return 0x1f0;
+	case 1:
+		return 0x170;
+	default:
+		return 0;
+	}
+}
+
+static void __init
+pplus_ide_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
+			  unsigned long ctrl_port, int *irq)
+{
+	unsigned long reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+
+	if (ctrl_port)
+		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	else
+		hw->io_ports[IDE_CONTROL_OFFSET] =
+		    hw->io_ports[IDE_DATA_OFFSET] + 0x206;
+
+	if (irq != NULL)
+		*irq = pplus_ide_default_irq(data_port);
+}
+#endif
+
+#ifdef CONFIG_SMP
+/* PowerPlus (MTX) support */
+static int __init smp_pplus_probe(void)
+{
+	extern int mot_multi;
+
+	if (mot_multi) {
+		openpic_request_IPIs();
+		smp_hw_index[1] = 1;
+		return 2;
+	}
+
+	return 1;
+}
+
+static void __init smp_pplus_kick_cpu(int nr)
+{
+	*(unsigned long *)KERNELBASE = nr;
+	asm volatile ("dcbf 0,%0"::"r" (KERNELBASE):"memory");
+	printk(KERN_INFO "CPU1 reset, waiting\n");
+}
+
+static void __init smp_pplus_setup_cpu(int cpu_nr)
+{
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+}
+
+static struct smp_ops_t pplus_smp_ops = {
+	smp_openpic_message_pass,
+	smp_pplus_probe,
+	smp_pplus_kick_cpu,
+	smp_pplus_setup_cpu,
+	.give_timebase = smp_generic_give_timebase,
+	.take_timebase = smp_generic_take_timebase,
+};
+#endif				/* CONFIG_SMP */
+
+#ifdef DUMP_DBATS
+static void print_dbat(int idx, u32 bat)
+{
+
+	char str[64];
+
+	sprintf(str, "DBAT%c%c = 0x%08x\n",
+		(char)((idx - DBAT0U) / 2) + '0', (idx & 1) ? 'L' : 'U', bat);
+	ppc_md.progress(str, 0);
+}
+
+#define DUMP_DBAT(x) \
+	do { \
+	u32 __temp = mfspr(x);\
+	print_dbat(x, __temp); \
+	} while (0)
+
+static void dump_dbats(void)
+{
+	if (ppc_md.progress) {
+		DUMP_DBAT(DBAT0U);
+		DUMP_DBAT(DBAT0L);
+		DUMP_DBAT(DBAT1U);
+		DUMP_DBAT(DBAT1L);
+		DUMP_DBAT(DBAT2U);
+		DUMP_DBAT(DBAT2L);
+		DUMP_DBAT(DBAT3U);
+		DUMP_DBAT(DBAT3L);
+	}
+}
+#endif
+
+static unsigned long __init pplus_find_end_of_memory(void)
+{
+	unsigned long total;
+
+	if (ppc_md.progress)
+		ppc_md.progress("pplus_find_end_of_memory", 0);
+
+#ifdef DUMP_DBATS
+	dump_dbats();
+#endif
+
+	total = pplus_get_mem_size(PPLUS_HAWK_SMC_BASE);
+	return (total);
+}
+
+static void __init pplus_map_io(void)
+{
+	io_block_mapping(PPLUS_ISA_IO_BASE, PPLUS_ISA_IO_BASE, 0x10000000,
+			 _PAGE_IO);
+	io_block_mapping(0xfef80000, 0xfef80000, 0x00080000, _PAGE_IO);
+}
+
+static void __init pplus_init2(void)
+{
+#ifdef CONFIG_NVRAM
+	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
+#endif
+	request_region(0x20, 0x20, "pic1");
+	request_region(0xa0, 0x20, "pic2");
+	request_region(0x00, 0x20, "dma1");
+	request_region(0x40, 0x20, "timer");
+	request_region(0x80, 0x10, "dma page reg");
+	request_region(0xc0, 0x20, "dma2");
+}
+
+/*
+ * Set BAT 2 to access 0x8000000 so progress messages will work and set BAT 3
+ * to 0xf0000000 to access Falcon/Raven or Hawk registers
+ */
+static __inline__ void pplus_set_bat(void)
+{
+	/* wait for all outstanding memory accesses to complete */
+	mb();
+
+	/* setup DBATs */
+	mtspr(DBAT2U, 0x80001ffe);
+	mtspr(DBAT2L, 0x8000002a);
+	mtspr(DBAT3U, 0xf0001ffe);
+	mtspr(DBAT3L, 0xf000002a);
+
+	/* wait for updates */
+	mb();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	/* Map in board regs, etc. */
+	pplus_set_bat();
+
+	isa_io_base = PREP_ISA_IO_BASE;
+	isa_mem_base = PREP_ISA_MEM_BASE;
+	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	ppc_md.setup_arch = pplus_setup_arch;
+	ppc_md.show_cpuinfo = pplus_show_cpuinfo;
+	ppc_md.irq_canonicalize = pplus_irq_canonicalize;
+	ppc_md.init_IRQ = pplus_init_IRQ;
+	/* this gets changed later on if we have an OpenPIC -- Cort */
+	ppc_md.get_irq = i8259_irq;
+	ppc_md.init = pplus_init2;
+
+	ppc_md.restart = pplus_restart;
+	ppc_md.power_off = pplus_power_off;
+	ppc_md.halt = pplus_halt;
+
+	TODC_INIT(TODC_TYPE_MK48T59, PREP_NVRAM_AS0, PREP_NVRAM_AS1,
+		  PREP_NVRAM_DATA, 8);
+
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.calibrate_decr = todc_calibrate_decr;
+	ppc_md.nvram_read_val = todc_m48txx_read_val;
+	ppc_md.nvram_write_val = todc_m48txx_write_val;
+
+	ppc_md.find_end_of_memory = pplus_find_end_of_memory;
+	ppc_md.setup_io_mappings = pplus_map_io;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+	ppc_ide_md.default_irq = pplus_ide_default_irq;
+	ppc_ide_md.default_io_base = pplus_ide_default_io_base;
+	ppc_ide_md.ide_init_hwif = pplus_ide_init_hwif_ports;
+#endif
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = gen550_progress;
+#endif				/* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops = &pplus_smp_ops;
+#endif				/* CONFIG_SMP */
+}
diff -Nru a/arch/ppc/platforms/pplus.h b/arch/ppc/platforms/pplus.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/pplus.h	Sat Apr  3 19:38:44 2004
@@ -0,0 +1,77 @@
+/*
+ * arch/ppc/platforms/pplus.h
+ *
+ * Definitions for Motorola MCG Falcon/Raven & HAWK North Bridge & Memory ctlr.
+ *
+ * Author: Mark A. Greerinclude/asm-ppc/hawk.h
+ *         mgreer@mvista.com
+ *
+ * Modified by Randy Vinson (rvinson@mvista.com)
+ *
+ * 2001-2004 (c) 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.
+ */
+
+#ifndef __PPC_PPLUS_H
+#define __PPC_PPLUS_H
+
+#include <asm/io.h>
+
+/*
+ * Due to limiations imposed by legacy hardware (primaryily IDE controllers),
+ * the PPLUS boards operate using a PReP address map.
+ *
+ * From Processor (physical) -> PCI:
+ *   PCI Mem Space: 0xc0000000 - 0xfe000000 -> 0x00000000 - 0x3e000000 (768 MB)
+ *   PCI I/O Space: 0x80000000 - 0x90000000 -> 0x00000000 - 0x10000000 (256 MB)
+ *	Note: Must skip 0xfe000000-0xfe400000 for CONFIG_HIGHMEM/PKMAP area
+ *
+ * From PCI -> Processor (physical):
+ *   System Memory: 0x80000000 -> 0x00000000
+ */
+
+#define PPLUS_ISA_MEM_BASE		PREP_ISA_MEM_BASE
+#define PPLUS_ISA_IO_BASE		PREP_ISA_IO_BASE
+
+/* PCI Memory space mapping info */
+#define PPLUS_PCI_MEM_SIZE		0x30000000U
+#define PPLUS_PROC_PCI_MEM_START	PPLUS_ISA_MEM_BASE
+#define PPLUS_PROC_PCI_MEM_END		(PPLUS_PROC_PCI_MEM_START +	\
+					 PPLUS_PCI_MEM_SIZE - 1)
+#define PPLUS_PCI_MEM_START		0x00000000U
+#define PPLUS_PCI_MEM_END		(PPLUS_PCI_MEM_START +	\
+					 PPLUS_PCI_MEM_SIZE - 1)
+
+/* PCI I/O space mapping info */
+#define PPLUS_PCI_IO_SIZE		0x10000000U
+#define PPLUS_PROC_PCI_IO_START		PPLUS_ISA_IO_BASE
+#define PPLUS_PROC_PCI_IO_END		(PPLUS_PROC_PCI_IO_START +	\
+					 PPLUS_PCI_IO_SIZE - 1)
+#define PPLUS_PCI_IO_START		0x00000000U
+#define PPLUS_PCI_IO_END		(PPLUS_PCI_IO_START + 	\
+					 PPLUS_PCI_IO_SIZE - 1)
+/* System memory mapping info */
+#define PPLUS_PCI_DRAM_OFFSET		PREP_PCI_DRAM_OFFSET
+#define PPLUS_PCI_PHY_MEM_OFFSET	(PPLUS_ISA_MEM_BASE-PPLUS_PCI_MEM_START)
+
+/* Define base addresses for important sets of registers */
+#define PPLUS_HAWK_SMC_BASE		0xfef80000U
+#define PPLUS_HAWK_PPC_REG_BASE		0xfeff0000U
+#define PPLUS_SYS_CONFIG_REG		0xfef80400U
+#define PPLUS_L2_CONTROL_REG		0x8000081cU
+
+#define PPLUS_VGA_MEM_BASE		0xf0000000U
+
+extern int pplus_init(struct pci_controller *hose,
+	       unsigned int ppc_reg_base, unsigned long processor_pci_mem_start,
+	       unsigned long processor_pci_mem_end,
+	       unsigned long processor_pci_io_start,
+	       unsigned long processor_pci_io_end,
+	       unsigned long processor_mpic_base);
+
+extern unsigned long pplus_get_mem_size(unsigned int smc_base);
+extern int pplus_mpic_init(unsigned int pci_mem_offset);
+
+#endif				/* __PPC_PPLUS_H */
diff -Nru a/arch/ppc/platforms/pplus_pci.c b/arch/ppc/platforms/pplus_pci.c
--- a/arch/ppc/platforms/pplus_pci.c	Sat Apr  3 19:38:57 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,530 +0,0 @@
-/*
- * arch/ppc/platforms/pplus_pci.c
- *
- * PCI setup for MCG PowerPlus
- *
- * Author: Randy Vinson <rvinson@mvista.com>
- *
- * Derived from original PowerPlus PReP work by
- * Cort Dougan, Johnnie Peters, Matt Porter, and
- * Troy Benjegerdes.
- *
- * 2001 (c) 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.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/sections.h>
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/ptrace.h>
-#include <asm/pci-bridge.h>
-#include <asm/residual.h>
-#include <asm/irq.h>
-#include <asm/machdep.h>
-
-#include <asm/open_pic.h>
-#include <asm/pplus.h>
-
-unsigned char *Motherboard_map_name;
-
-/* Tables for known hardware */
-
-/* Motorola Mesquite */
-static inline int
-mesquite_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-	/*
-	 * 	MPIC interrupts for various IDSEL values (MPIC IRQ0 =
-	 * 	Linux IRQ16 (to leave room for ISA IRQs at 0-15).
-	 *      PCI IDSEL/INTPIN->INTLINE
-	 *         A   B   C   D
-	 */
-	{
-		{ 18,  0,  0,  0 },     /* IDSEL 14 - Enet 0 */
-		{  0,  0,  0,  0 },     /* IDSEL 15 - unused */
-		{ 19, 19, 19, 19 },     /* IDSEL 16 - PMC Slot 1 */
-		{  0,  0,  0,  0 },     /* IDSEL 17 - unused */
-		{  0,  0,  0,  0 },     /* IDSEL 18 - unused */
-		{  0,  0,  0,  0 },     /* IDSEL 19 - unused */
-		{ 24, 25, 26, 27 },     /* IDSEL 20 - P2P bridge (to cPCI 1) */
-		{  0,  0,  0,  0 },     /* IDSEL 21 - unused */
-		{ 28, 29, 30, 31 }      /* IDSEL 22 - P2P bridge (to cPCI 2) */
-	};
-
-	const long min_idsel = 14, max_idsel = 22, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-}
-
-/* Motorola Sitka */
-static inline int
-sitka_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-	/*
-	 * 	MPIC interrupts for various IDSEL values (MPIC IRQ0 =
-	 * 	Linux IRQ16 (to leave room for ISA IRQs at 0-15).
-	 *      PCI IDSEL/INTPIN->INTLINE
-	 *         A   B   C   D
-	 */
-	{
-		{ 18,  0,  0,  0 },     /* IDSEL 14 - Enet 0 */
-		{  0,  0,  0,  0 },     /* IDSEL 15 - unused */
-		{ 25, 26, 27, 28 },     /* IDSEL 16 - PMC Slot 1 */
-		{ 28, 25, 26, 27 },     /* IDSEL 17 - PMC Slot 2 */
-		{  0,  0,  0,  0 },     /* IDSEL 18 - unused */
-		{  0,  0,  0,  0 },     /* IDSEL 19 - unused */
-		{ 20,  0,  0,  0 }      /* IDSEL 20 - P2P bridge (to cPCI) */
-	};
-
-	const long min_idsel = 14, max_idsel = 20, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-}
-
-/* Motorola MTX */
-static inline int
-MTX_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-	/*
-	 * 	MPIC interrupts for various IDSEL values (MPIC IRQ0 =
-	 * 	Linux IRQ16 (to leave room for ISA IRQs at 0-15).
-	 *      PCI IDSEL/INTPIN->INTLINE
-	 *         A   B   C   D
-	 */
-	{
-		{ 19,  0,  0,  0 },     /* IDSEL 12 - SCSI   */
-		{ 0,   0,  0,  0 },     /* IDSEL 13 - unused */
-		{ 18,  0,  0,  0 },     /* IDSEL 14 - Enet   */
-		{  0,  0,  0,  0 },     /* IDSEL 15 - unused */
-		{ 25, 26, 27, 28 },     /* IDSEL 16 - PMC Slot 1 */
-		{ 26, 27, 28, 25 },     /* IDSEL 17 - PMC Slot 2 */
-		{ 27, 28, 25, 26 }      /* IDSEL 18 - PCI Slot 3 */
-	};
-
-	const long min_idsel = 12, max_idsel = 18, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-}
-
-/* Motorola MTX Plus */
-/* Secondary bus interrupt routing is not supported yet */
-static inline int
-MTXplus_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-	/*
-	 * 	MPIC interrupts for various IDSEL values (MPIC IRQ0 =
-	 * 	Linux IRQ16 (to leave room for ISA IRQs at 0-15).
-	 *      PCI IDSEL/INTPIN->INTLINE
-	 *         A   B   C   D
-	 */
-	{
-		{ 19,  0,  0,  0 },     /* IDSEL 12 - SCSI   */
-		{ 0,   0,  0,  0 },     /* IDSEL 13 - unused */
-		{ 18,  0,  0,  0 },     /* IDSEL 14 - Enet 1 */
-		{  0,  0,  0,  0 },     /* IDSEL 15 - unused */
-		{ 25, 26, 27, 28 },     /* IDSEL 16 - PCI Slot 1P */
-		{ 26, 27, 28, 25 },     /* IDSEL 17 - PCI Slot 2P */
-		{ 27, 28, 25, 26 },     /* IDSEL 18 - PCI Slot 3P */
-		{ 26,  0,  0,  0 },	/* IDSEL 19 - Enet 2 */
-		{  0,  0,  0,  0 } 	/* IDSEL 20 - P2P Bridge */
-	};
-
-	const long min_idsel = 12, max_idsel = 20, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-}
-
-static inline int
-Genesis2_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	/* 2600
-	 * Raven 31
-	 * ISA   11
-	 * SCSI	 12 - IRQ3
-	 * Univ  13
-	 * eth   14 - IRQ2
-	 * VGA   15 - IRQ4
-	 * PMC1  16 - IRQ9,10,11,12 = PMC1 A-D
-	 * PMC2  17 - IRQ12,9,10,11 = A-D
-	 * SCSI2 18 - IRQ11
-	 * eth2  19 - IRQ10
-	 * PCIX  20 - IRQ9,10,11,12 = PCI A-D
-	 */
-
-	/* 2400
-	 * Hawk 31
-	 * ISA	11
-	 * Univ 13
-	 * eth  14 - IRQ2
-	 * PMC1 16 - IRQ9,10,11,12 = PMC A-D
-	 * PMC2 17 - IRQ12,9,10,11 = PMC A-D
-	 * PCIX 20 - IRQ9,10,11,12 = PMC A-D
-	 */
-
-	/* 2300
-	 * Raven 31
-	 * ISA   11
-	 * Univ  13
-	 * eth   14 - IRQ2
-	 * PMC1  16 - 9,10,11,12 = A-D
-	 * PMC2  17 - 9,10,11,12 = B,C,D,A
-	 */
-
-	static char pci_irq_table[][4] =
-	/*
-	 * 	MPIC interrupts for various IDSEL values (MPIC IRQ0 =
-	 * 	Linux IRQ16 (to leave room for ISA IRQs at 0-15).
-	 *      PCI IDSEL/INTPIN->INTLINE
-	 *         A   B   C   D
-	 */
-	{
-		{ 19,  0,  0,  0 },     /* IDSEL 12 - SCSI   */
-		{ 0,   0,  0,  0 },     /* IDSEL 13 - Universe PCI - VME */
-		{ 18,  0,  0,  0 },     /* IDSEL 14 - Enet 1 */
-		{  0,  0,  0,  0 },     /* IDSEL 15 - unused */
-		{ 25, 26, 27, 28 },     /* IDSEL 16 - PCI/PMC Slot 1P */
-		{ 28, 25, 26, 27 },     /* IDSEL 17 - PCI/PMC Slot 2P */
-		{ 27, 28, 25, 26 },     /* IDSEL 18 - PCI Slot 3P */
-		{ 26,  0,  0,  0 },	/* IDSEL 19 - Enet 2 */
-		{ 25, 26, 27, 28 } 	/* IDSEL 20 - P2P Bridge */
-	};
-
-	const long min_idsel = 12, max_idsel = 20, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-}
-
-#define MOTOROLA_CPUTYPE_REG	0x800
-#define MOTOROLA_BASETYPE_REG	0x803
-#define MPIC_RAVEN_ID		0x48010000
-#define	MPIC_HAWK_ID		0x48030000
-#define	MOT_PROC2_BIT		0x800
-
-static u_char pplus_openpic_initsenses[] __initdata = {
-    1,	/* MVME2600_INT_SIO */
-    0,	/* MVME2600_INT_FALCN_ECC_ERR */
-    1,	/* MVME2600_INT_PCI_ETHERNET */
-    1,	/* MVME2600_INT_PCI_SCSI */
-    1,	/* MVME2600_INT_PCI_GRAPHICS */
-    1,	/* MVME2600_INT_PCI_VME0 */
-    1,	/* MVME2600_INT_PCI_VME1 */
-    1,	/* MVME2600_INT_PCI_VME2 */
-    1,	/* MVME2600_INT_PCI_VME3 */
-    1,	/* MVME2600_INT_PCI_INTA */
-    1,	/* MVME2600_INT_PCI_INTB */
-    1,	/* MVME2600_INT_PCI_INTC */
-    1,	/* MVME2600_INT_PCI_INTD */
-    1,	/* MVME2600_INT_LM_SIG0 */
-    1,	/* MVME2600_INT_LM_SIG1 */
-};
-
-int mot_entry = -1;
-int prep_keybd_present = 1;
-int mot_multi = 0;
-
-int __init raven_init(void)
-{
-	unsigned short	devid;
-	unsigned char	base_mod;
-
-	/* set the MPIC base address */
-	early_write_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, 0x3cfc0000);
-
-	pplus_mpic_init(PREP_ISA_MEM_BASE);
-
-	OpenPIC_InitSenses = pplus_openpic_initsenses;
-	OpenPIC_NumInitSenses = sizeof(pplus_openpic_initsenses);
-
-	ppc_md.get_irq = openpic_get_irq;
-
-	/* This is a hack.  If this is a 2300 or 2400 mot board then there is
-	 * no keyboard controller and we have to indicate that.
-	 */
-
-	early_read_config_word(0, 0, 0, PCI_VENDOR_ID, &devid);
-	base_mod = inb(MOTOROLA_BASETYPE_REG);
-	if ((devid == PCI_DEVICE_ID_MOTOROLA_HAWK) ||
-	    (base_mod == 0xF9) ||
-	    (base_mod == 0xFA) || (base_mod == 0xE1))
-		prep_keybd_present = 0;
-
-	return 1;
-}
-
-struct brd_info {
-	int		cpu_type;	/* 0x100 mask assumes for Raven and Hawk boards that the level/edge are set */
-					/* 0x200 if this board has a Hawk chip. */
-	int		base_type;
-	int		max_cpu;	/* ored with 0x80 if this board should be checked for multi CPU */
-	const char	*name;
-	int		(*map_irq)(struct pci_dev *,
-			           unsigned char,
-				   unsigned char);
-};
-struct brd_info mot_info[] = {
-	{0x300, 0x00, 0x00, "MVME 2400", Genesis2_map_irq},
-	{0x1E0, 0xE0, 0x00, "Mesquite cPCI (MCP750)", mesquite_map_irq},
-	{0x1E0, 0xE1, 0x00, "Sitka cPCI (MCPN750)", sitka_map_irq},
-	{0x1E0, 0xE2, 0x00, "Mesquite cPCI (MCP750) w/ HAC", mesquite_map_irq},
-	{0x1E0, 0xF6, 0x80, "MTX Plus",	MTXplus_map_irq},
-	{0x1E0, 0xF6, 0x81, "Dual MTX Plus", MTXplus_map_irq},
-	{0x1E0, 0xF7, 0x80, "MTX wo/ Parallel Port", MTX_map_irq},
-	{0x1E0, 0xF7, 0x81, "Dual MTX wo/ Parallel Port", MTX_map_irq},
-	{0x1E0, 0xF8, 0x80, "MTX w/ Parallel Port", MTX_map_irq},
-	{0x1E0, 0xF8, 0x81, "Dual MTX w/ Parallel Port", MTX_map_irq},
-	{0x1E0, 0xF9, 0x00, "MVME 2300", Genesis2_map_irq},
-	{0x1E0, 0xFA, 0x00, "MVME 2300SC/2600",	Genesis2_map_irq},
-	{0x1E0, 0xFB, 0x00, "MVME 2600 with MVME712M", Genesis2_map_irq},
-	{0x1E0, 0xFC, 0x00, "MVME 2600/2700 with MVME761", Genesis2_map_irq},
-	{0x1E0, 0xFD, 0x80, "MVME 3600 with MVME712M", Genesis2_map_irq},
-	{0x1E0, 0xFD, 0x81, "MVME 4600 with MVME712M", Genesis2_map_irq},
-	{0x1E0, 0xFE, 0x80, "MVME 3600 with MVME761", Genesis2_map_irq},
-	{0x1E0, 0xFE, 0x81, "MVME 4600 with MVME761", Genesis2_map_irq},
-	{0x000, 0x00, 0x00, "",	NULL}
-};
-
-void __init pplus_set_board_type(void)
-{
-	unsigned char  cpu_type;
-	unsigned char  base_mod;
-	int	       entry;
-	unsigned short devid;
-	unsigned long  *ProcInfo = NULL;
-
-	cpu_type = inb(MOTOROLA_CPUTYPE_REG) & 0xF0;
-	base_mod = inb(MOTOROLA_BASETYPE_REG);
-	early_read_config_word(0, 0, 0, PCI_VENDOR_ID, &devid);
-
-	for (entry = 0; mot_info[entry].cpu_type != 0; entry++) {
-
-		/* Check for Hawk chip */
-		if (mot_info[entry].cpu_type & 0x200) {
-			if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK)
-				continue;
-		} else {
-			/* store the system config register for later use. */
-			ProcInfo = (unsigned long *)ioremap(0xfef80400, 4);
-
-			/* Check non hawk boards */
-			if ((mot_info[entry].cpu_type & 0xff) != cpu_type)
-				continue;
-
-			if (mot_info[entry].base_type == 0) {
-				mot_entry = entry;
-				break;
-			}
-
-			if (mot_info[entry].base_type != base_mod)
-				continue;
-		}
-
-		if (!(mot_info[entry].max_cpu & 0x80)) {
-			mot_entry = entry;
-			break;
-		}
-
-		/* processor 1 not present and max processor zero indicated */
-		if ((*ProcInfo & MOT_PROC2_BIT) && !(mot_info[entry].max_cpu & 0x7f)) {
-			mot_entry = entry;
-			break;
-		}
-
-		/* processor 1 present and max processor zero indicated */
-		if (!(*ProcInfo & MOT_PROC2_BIT) && (mot_info[entry].max_cpu & 0x7f)) {
-			mot_entry = entry;
-			break;
-		}
-
-		/* Indicate to system if this is a multiprocessor board */
-		if (!(*ProcInfo & MOT_PROC2_BIT)) {
-			mot_multi = 1;
-						        }
-	}
-
-	if (mot_entry == -1)
-
-		/* No particular cpu type found - assume Mesquite (MCP750) */
-		mot_entry = 1;
-
-	Motherboard_map_name = (unsigned char *)mot_info[mot_entry].name;
-	ppc_md.pci_map_irq = mot_info[mot_entry].map_irq;
-}
-void __init
-pplus_pib_init(void)
-{
-	unsigned char   reg;
-	unsigned short  short_reg;
-
-	struct pci_dev *dev = NULL;
-
-	/*
-	 * Perform specific configuration for the Via Tech or
-	 * or Winbond PCI-ISA-Bridge part.
-	 */
-	if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
-					PCI_DEVICE_ID_VIA_82C586_1, dev))) {
-		/*
-		 * PPCBUG does not set the enable bits
-		 * for the IDE device. Force them on here.
-		 */
-		pci_read_config_byte(dev, 0x40, &reg);
-
-		reg |= 0x03; /* IDE: Chip Enable Bits */
-		pci_write_config_byte(dev, 0x40, reg);
-	}
-	if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
-					PCI_DEVICE_ID_VIA_82C586_2,
-					dev)) && (dev->devfn = 0x5a)) {
-		/* Force correct USB interrupt */
-		dev->irq = 11;
-		pci_write_config_byte(dev,
-				PCI_INTERRUPT_LINE,
-				dev->irq);
-	}
-	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
-					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
-		/* Clear PCI Interrupt Routing Control Register. */
-		short_reg = 0x0000;
-		pci_write_config_word(dev, 0x44, short_reg);
-		/* Route IDE interrupts to IRQ 14 */
-		reg = 0xEE;
-		pci_write_config_byte(dev, 0x43, reg);
-	}
-
-	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
-					PCI_DEVICE_ID_WINBOND_82C105, dev))){
-		/*
-		 * Disable LEGIRQ mode so PCI INTS are routed
-		 * directly to the 8259 and enable both channels
-		 */
-		pci_write_config_dword(dev, 0x40, 0x10ff0033);
-
-		/* Force correct IDE interrupt */
-		dev->irq = 14;
-		pci_write_config_byte(dev,
-				PCI_INTERRUPT_LINE,
-				dev->irq);
-	}
-}
-
-void __init
-pplus_set_VIA_IDE_legacy(void)
-{
-	unsigned short vend, dev;
-
-	early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
-	early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
-
-	if ((vend == PCI_VENDOR_ID_VIA) &&
-	    (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
-
-		unsigned char temp;
-
-		/* put back original "standard" port base addresses */
-		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-				         PCI_BASE_ADDRESS_0, 0x1f1);
-		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-				         PCI_BASE_ADDRESS_1, 0x3f5);
-		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-				         PCI_BASE_ADDRESS_2, 0x171);
-		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-				         PCI_BASE_ADDRESS_3, 0x375);
-		early_write_config_dword(0, 0, PCI_DEVFN(0xb, 1),
-				         PCI_BASE_ADDRESS_4, 0xcc01);
-
-		/* put into legacy mode */
-		early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
-				       &temp);
-		temp &= ~0x05;
-		early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
-					temp);
-	}
-}
-
-void
-pplus_set_VIA_IDE_native(void)
-{
-	unsigned short vend, dev;
-
-	early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_VENDOR_ID, &vend);
-	early_read_config_word(0, 0, PCI_DEVFN(0xb, 1), PCI_DEVICE_ID, &dev);
-
-	if ((vend == PCI_VENDOR_ID_VIA) &&
-	    (dev == PCI_DEVICE_ID_VIA_82C586_1)) {
-
-		unsigned char temp;
-
-		/* put into native mode */
-		early_read_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
-				       &temp);
-		temp |= 0x05;
-		early_write_config_byte(0, 0, PCI_DEVFN(0xb, 1), PCI_CLASS_PROG,
-					temp);
-	}
-}
-
-void __init
-pplus_pcibios_fixup(void)
-{
-
-	printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name);
-
-	/* Setup the Winbond or Via PIB */
-	pplus_pib_init();
-}
-
-static void __init
-pplus_init_resource(struct resource *res, unsigned long start,
-		   unsigned long end, int flags)
-{
-	res->flags = flags;
-	res->start = start;
-	res->end = end;
-	res->name = "PCI host bridge";
-	res->parent = NULL;
-	res->sibling = NULL;
-	res->child = NULL;
-}
-
-void __init
-pplus_setup_hose(void)
-{
-	struct pci_controller* hose;
-
-	hose = pcibios_alloc_controller();
-	if (!hose)
-		return;
-
-	hose->first_busno = 0;
-	hose->last_busno = 0xff;
-
-	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
-	hose->io_base_virt = (void *)PREP_ISA_IO_BASE;
-
-	pplus_init_resource(&hose->io_resource, 0x00000000, 0x0fffffff,
-			    IORESOURCE_IO);
-	pplus_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfdffffff,
-			    IORESOURCE_MEM);
-
-	hose->io_space.start  = 0x00000000;
-	hose->io_space.end    = 0x0fffffff;
-	hose->mem_space.start = 0x00000000;
-	hose->mem_space.end   = 0x3cfbffff; /* MPIC at 0x3cfc0000-0x3dffffff */
-
-	setup_indirect_pci(hose, 0x80000cf8, 0x80000cfc);
-
-	pplus_set_VIA_IDE_legacy();
-
-	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
-
-	ppc_md.pcibios_fixup = pplus_pcibios_fixup;
-	ppc_md.pci_swizzle = common_swizzle;
-	pplus_set_board_type();
-}
diff -Nru a/arch/ppc/platforms/pplus_setup.c b/arch/ppc/platforms/pplus_setup.c
--- a/arch/ppc/platforms/pplus_setup.c	Sat Apr  3 19:38:56 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,507 +0,0 @@
-/*
- * arch/ppc/platforms/pplus_setup.c
- *
- * Board setup routines for MCG PowerPlus
- *
- * Author: Randy Vinson <rvinson@mvista.com>
- *
- * Derived from original PowerPlus PReP work by
- * Cort Dougan, Johnnie Peters, Matt Porter, and
- * Troy Benjegerdes.
- *
- * 2001-2002 (c) 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.
- */
-
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.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>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/initrd.h>
-#include <linux/ioport.h>
-#include <linux/console.h>
-#include <linux/timex.h>
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <linux/ide.h>
-#include <linux/kdev_t.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-
-#include <asm/sections.h>
-#include <asm/mmu.h>
-#include <asm/system.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/cache.h>
-#include <asm/dma.h>
-#include <asm/machdep.h>
-#include <asm/mk48t59.h>
-#include <asm/prep_nvram.h>
-#include <asm/raven.h>
-#include <asm/vga.h>
-#include <asm/time.h>
-
-#include <asm/i8259.h>
-#include <asm/open_pic.h>
-#include <asm/pplus.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-
-#undef DUMP_DBATS
-
-TODC_ALLOC();
-
-extern char saved_command_line[];
-
-extern void pplus_setup_hose(void);
-extern void pplus_set_VIA_IDE_native(void);
-
-extern unsigned long loops_per_jiffy;
-
-static int
-pplus_show_cpuinfo(struct seq_file *m)
-{
-	extern char *Motherboard_map_name;
-
-	seq_printf(m, "vendor\t\t: Motorola MCG\n");
-	seq_printf(m, "machine\t\t: %s\n", Motherboard_map_name);
-
-	return 0;
-}
-
-static void __init
-pplus_setup_arch(void)
-{
-	unsigned char reg;
-
-	if ( ppc_md.progress )
-		ppc_md.progress("pplus_setup_arch: enter\n", 0);
-
-	/* init to some ~sane value until calibrate_delay() runs */
-	loops_per_jiffy = 50000000;
-
-	if ( ppc_md.progress )
-		ppc_md.progress("pplus_setup_arch: find_bridges\n", 0);
-
-	/* Setup PCI host bridge */
-	pplus_setup_hose();
-
-	/* Set up floppy in PS/2 mode */
-	outb(0x09, SIO_CONFIG_RA);
-	reg = inb(SIO_CONFIG_RD);
-	reg = (reg & 0x3F) | 0x40;
-	outb(reg, SIO_CONFIG_RD);
-	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
-
-	/* Enable L2.  Assume we don't need to flush -- Cort*/
-	*(unsigned char *)(0x8000081c) |= 3;
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start)
-		ROOT_DEV = Root_RAM0;
-	else
-#endif
-#ifdef CONFIG_ROOT_NFS
-		ROOT_DEV = Root_NFS;
-#else
-		ROOT_DEV = Root_SDA2;
-#endif
-
-	printk(KERN_INFO "Motorola PowerPlus Platform\n");
-	printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
-
-	if ( ppc_md.progress )
-		ppc_md.progress("pplus_setup_arch: raven_init\n", 0);
-
-	raven_init();
-
-#ifdef CONFIG_VGA_CONSOLE
-	/* remap the VGA memory */
-	vgacon_remap_base = 0xf0000000;
-	conswitchp = &vga_con;
-#elif defined(CONFIG_DUMMY_CONSOLE)
-	conswitchp = &dummy_con;
-#endif
-#ifdef CONFIG_PPCBUG_NVRAM
-	/* Read in NVRAM data */
-	init_prep_nvram();
-
-	/* if no bootargs, look in NVRAM */
-	if ( cmd_line[0] == '\0' ) {
-		char *bootargs;
-		 bootargs = prep_nvram_get_var("bootargs");
-		 if (bootargs != NULL) {
-			 strcpy(cmd_line, bootargs);
-			 /* again.. */
-			 strcpy(saved_command_line, cmd_line);
-		}
-	}
-#endif
-	if ( ppc_md.progress )
-		ppc_md.progress("pplus_setup_arch: exit\n", 0);
-}
-
-static void
-pplus_restart(char *cmd)
-{
-	unsigned long i = 10000;
-
-	local_irq_disable();
-
-	/* set VIA IDE controller into native mode */
-	pplus_set_VIA_IDE_native();
-
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(0, MSR_IP);
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(0x92) & ~1L , 0x92 );
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(0x92) | 1 , 0x92 );
-
-	while ( i != 0 ) i++;
-	panic("restart failed\n");
-}
-
-static void
-pplus_halt(void)
-{
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(MSR_EE, MSR_IP);
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(0x92) & ~1L , 0x92 );
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(0x92) | 1 , 0x92 );
-
-	while ( 1 ) ;
-	/*
-	 * Not reached
-	 */
-}
-
-static void
-pplus_power_off(void)
-{
-	pplus_halt();
-}
-
-static unsigned int
-pplus_irq_canonicalize(u_int irq)
-{
-	if (irq == 2)
-	{
-		return 9;
-	}
-	else
-	{
-		return irq;
-	}
-}
-
-static void __init
-pplus_init_IRQ(void)
-{
-	int i;
-
-	if (OpenPIC_Addr != NULL)
-		openpic_init(1, NUM_8259_INTERRUPTS, 0, -1);
-	for ( i = 0 ; i < NUM_8259_INTERRUPTS ; i++ )
-		irq_desc[i].handler = &i8259_pic;
-	i8259_init(NULL);
-}
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-/*
- * IDE stuff.
- */
-static int
-pplus_ide_default_irq(unsigned long base)
-{
-	switch (base) {
-		case 0x1f0: return 14;
-		case 0x170: return 15;
-		default: return 0;
-	}
-}
-
-static unsigned long
-pplus_ide_default_io_base(int index)
-{
-	switch (index) {
-		case 0: return 0x1f0;
-		case 1: return 0x170;
-		default:
-			return 0;
-	}
-}
-
-static void __init
-pplus_ide_init_hwif_ports (hw_regs_t *hw, unsigned long data_port, unsigned long ctrl_port, int *irq)
-{
-	unsigned long reg = data_port;
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
-	}
-	if (irq != NULL)
-		*irq = pplus_ide_default_irq(data_port);
-}
-#endif
-
-#ifdef CONFIG_SMP
-/* PowerPlus (MTX) support */
-static int __init
-smp_pplus_probe(void)
-{
-	extern int mot_multi;
-
-	if (mot_multi) {
-		openpic_request_IPIs();
-		smp_hw_index[1] = 1;
-		return 2;
-	}
-
-	return 1;
-}
-
-static void __init
-smp_pplus_kick_cpu(int nr)
-{
-	*(unsigned long *)KERNELBASE = nr;
-	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-	printk("CPU1 reset, waiting\n");
-}
-
-static void __init
-smp_pplus_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-}
-
-static struct smp_ops_t pplus_smp_ops = {
-	smp_openpic_message_pass,
-	smp_pplus_probe,
-	smp_pplus_kick_cpu,
-	smp_pplus_setup_cpu,
-	.give_timebase = smp_generic_give_timebase,
-	.take_timebase = smp_generic_take_timebase,
-};
-#endif /* CONFIG_SMP */
-
-#ifdef DUMP_DBATS
-static void print_dbat(int idx, u32 bat) {
-
-	char str[64];
-
-	sprintf(str, "DBAT%c%c = 0x%08x\n",
-		(char)((idx - DBAT0U) / 2) + '0',
-		(idx & 1) ? 'L' : 'U', bat);
-	ppc_md.progress(str, 0);
-}
-
-#define DUMP_DBAT(x) \
-	do { \
-	u32 __temp = mfspr(x);\
-	print_dbat(x, __temp); \
-	} while (0)
-
-static void dump_dbats(void) {
-
-	if (ppc_md.progress) {
-		DUMP_DBAT(DBAT0U);
-		DUMP_DBAT(DBAT0L);
-		DUMP_DBAT(DBAT1U);
-		DUMP_DBAT(DBAT1L);
-		DUMP_DBAT(DBAT2U);
-		DUMP_DBAT(DBAT2L);
-		DUMP_DBAT(DBAT3U);
-		DUMP_DBAT(DBAT3L);
-	}
-}
-#endif
-
-static unsigned long __init
-pplus_find_end_of_memory(void)
-{
-	unsigned long total;
-
-	if (ppc_md.progress)
-		ppc_md.progress("pplus_find_end_of_memory\n",0);
-
-#ifdef DUMP_DBATS
-	dump_dbats();
-#endif
-
-	total = pplus_get_mem_size(0xfef80000);
-	return (total);
-}
-
-static void __init
-pplus_map_io(void)
-{
-	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
-	io_block_mapping(0xf0000000, 0xc0000000, 0x08000000, _PAGE_IO);
-}
-
-static void __init
-pplus_init2(void)
-{
-#ifdef CONFIG_NVRAM
-	request_region(PREP_NVRAM_AS0, 0x8, "nvram");
-#endif
-	request_region(0x20,0x20,"pic1");
-	request_region(0xa0,0x20,"pic2");
-	request_region(0x00,0x20,"dma1");
-	request_region(0x40,0x20,"timer");
-	request_region(0x80,0x10,"dma page reg");
-	request_region(0xc0,0x20,"dma2");
-}
-
-/*
- * Set BAT 2 to access 0x8000000 so progress messages will work and set BAT 3
- * to 0xf0000000 to access Falcon/Raven or Hawk registers
- */
-static __inline__ void
-pplus_set_bat(void)
-{
-	static int      mapping_set = 0;
-
-	if (!mapping_set) {
-
-		/* wait for all outstanding memory accesses to complete */
-		mb();
-
-		/* setup DBATs */
-		mtspr(DBAT2U, 0x80001ffe);
-		mtspr(DBAT2L, 0x8000002a);
-		mtspr(DBAT3U, 0xf0001ffe);
-		mtspr(DBAT3L, 0xf000002a);
-
-		/* wait for updates */
-		mb();
-
-		mapping_set = 1;
-	}
-
-	return;
-}
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-#include <asm/serial.h>
-
-static struct serial_state rs_table[RS_TABLE_SIZE] = {
-	SERIAL_PORT_DFNS        /* Defined in <asm/serial.h> */
-};
-
-	void
-pplus_progress(char *s, unsigned short hex)
-{
-	volatile char c;
-	volatile unsigned long com_port;
-	u16 shift;
-
-	com_port = rs_table[0].port + isa_io_base;
-	shift = rs_table[0].iomem_reg_shift;
-
-	while ((c = *s++) != 0) {
-		while ((*((volatile unsigned char *)com_port +
-						(UART_LSR << shift)) & UART_LSR_THRE) == 0)
-			;
-		*(volatile unsigned char *)com_port = c;
-
-		if (c == '\n') {
-			while ((*((volatile unsigned char *)com_port +
-							(UART_LSR << shift)) & UART_LSR_THRE) == 0)
-				;
-			*(volatile unsigned char *)com_port = '\r';
-		}
-	}
-}
-#endif  /* CONFIG_SERIAL_TEXT_DEBUG */
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-		unsigned long r6, unsigned long r7)
-{
-	parse_bootinfo(find_bootinfo());
-
-	/* Map in board regs, etc. */
-	pplus_set_bat();
-
-	isa_io_base = PREP_ISA_IO_BASE;
-	isa_mem_base = PREP_ISA_MEM_BASE;
-	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
-	ISA_DMA_THRESHOLD = 0x00ffffff;
-	DMA_MODE_READ = 0x44;
-	DMA_MODE_WRITE = 0x48;
-
-	ppc_md.setup_arch     = pplus_setup_arch;
-	ppc_md.show_percpuinfo = NULL;
-	ppc_md.show_cpuinfo    = pplus_show_cpuinfo;
-	ppc_md.irq_canonicalize = pplus_irq_canonicalize;
-	ppc_md.init_IRQ       = pplus_init_IRQ;
-	/* this gets changed later on if we have an OpenPIC -- Cort */
-	ppc_md.get_irq        = i8259_irq;
-	ppc_md.init           = pplus_init2;
-
-	ppc_md.restart        = pplus_restart;
-	ppc_md.power_off      = pplus_power_off;
-	ppc_md.halt           = pplus_halt;
-
-	TODC_INIT(TODC_TYPE_MK48T59, PREP_NVRAM_AS0, PREP_NVRAM_AS1,
-		  PREP_NVRAM_DATA, 8);
-
-	ppc_md.time_init      = todc_time_init;
-	ppc_md.set_rtc_time   = todc_set_rtc_time;
-	ppc_md.get_rtc_time   = todc_get_rtc_time;
-	ppc_md.calibrate_decr = todc_calibrate_decr;
-	ppc_md.nvram_read_val = todc_m48txx_read_val;
-	ppc_md.nvram_write_val = todc_m48txx_write_val;
-
-	ppc_md.find_end_of_memory = pplus_find_end_of_memory;
-	ppc_md.setup_io_mappings = pplus_map_io;
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-	ppc_md.progress = pplus_progress;
-#endif
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-	ppc_ide_md.default_irq = pplus_ide_default_irq;
-	ppc_ide_md.default_io_base = pplus_ide_default_io_base;
-	ppc_ide_md.ide_init_hwif = pplus_ide_init_hwif_ports;
-#endif
-
-#ifdef CONFIG_SMP
-	ppc_md.smp_ops		 = &pplus_smp_ops;
-#endif /* CONFIG_SMP */
-}
diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
--- a/arch/ppc/platforms/prep_setup.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc/platforms/prep_setup.c	Sat Apr  3 19:38:55 2004
@@ -49,6 +49,7 @@
 #include <asm/cache.h>
 #include <asm/dma.h>
 #include <asm/machdep.h>
+#include <asm/mc146818rtc.h>
 #include <asm/mk48t59.h>
 #include <asm/prep_nvram.h>
 #include <asm/raven.h>
@@ -1023,8 +1024,10 @@
 
 	ppc_md.time_init      = todc_time_init;
 	if (_prep_type == _PREP_IBM) {
-		TODC_INIT(TODC_TYPE_MC146818, PREP_NVRAM_AS0, PREP_NVRAM_AS1,
-				PREP_NVRAM_DATA, 8);
+		ppc_md.rtc_read_val = todc_mc146818_read_val;
+		ppc_md.rtc_write_val = todc_mc146818_write_val;
+		TODC_INIT(TODC_TYPE_MC146818, RTC_PORT(0), NULL, RTC_PORT(1),
+				8);
 	} else {
 		TODC_INIT(TODC_TYPE_MK48T59, PREP_NVRAM_AS0, PREP_NVRAM_AS1,
 				PREP_NVRAM_DATA, 8);
diff -Nru a/arch/ppc/platforms/proc_rtas.c b/arch/ppc/platforms/proc_rtas.c
--- a/arch/ppc/platforms/proc_rtas.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc/platforms/proc_rtas.c	Sat Apr  3 19:38:56 2004
@@ -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 @@
 /* ****************************************************************** */
 /* 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 @@
 
 	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 -Nru a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/platforms/spruce.c	Sat Apr  3 19:38:41 2004
@@ -0,0 +1,330 @@
+/*
+ * arch/ppc/platforms/spruce.c
+ *
+ * Board and PCI setup routines for IBM Spruce
+ *
+ * Author: MontaVista Software <source@mvista.com>
+ *
+ * 2000-2004 (c) 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.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/ide.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/bootinfo.h>
+#include <asm/kgdb.h>
+
+#include <syslib/cpc700.h>
+
+#include "spruce.h"
+
+static inline int
+spruce_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
+{
+	static char pci_irq_table[][4] =
+		/*
+		 * 	PCI IDSEL/INTPIN->INTLINE
+		 * 	A	B	C	D
+		 */
+	{
+		{23, 24, 25, 26},	/* IDSEL 1 - PCI slot 3 */
+		{24, 25, 26, 23},	/* IDSEL 2 - PCI slot 2 */
+		{25, 26, 23, 24},	/* IDSEL 3 - PCI slot 1 */
+		{26, 23, 24, 25},	/* IDSEL 4 - PCI slot 0 */
+	};
+
+	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
+	return PCI_IRQ_TABLE_LOOKUP;
+}
+
+static void __init
+spruce_setup_hose(void)
+{
+	struct pci_controller *hose;
+
+	/* Setup hose */
+	hose = pcibios_alloc_controller();
+	if (!hose)
+		return;
+
+	hose->first_busno = 0;
+	hose->last_busno = 0xff;
+
+	pci_init_resource(&hose->io_resource,
+			SPRUCE_PCI_LOWER_IO,
+			SPRUCE_PCI_UPPER_IO,
+			IORESOURCE_IO,
+			"PCI host bridge");
+
+	pci_init_resource(&hose->mem_resources[0],
+			SPRUCE_PCI_LOWER_MEM,
+			SPRUCE_PCI_UPPER_MEM,
+			IORESOURCE_MEM,
+			"PCI host bridge");
+
+	hose->io_space.start = SPRUCE_PCI_LOWER_IO;
+	hose->io_space.end = SPRUCE_PCI_UPPER_IO;
+	hose->mem_space.start = SPRUCE_PCI_LOWER_MEM;
+	hose->mem_space.end = SPRUCE_PCI_UPPER_MEM;
+	hose->io_base_virt = (void *)SPRUCE_ISA_IO_BASE;
+
+	setup_indirect_pci(hose,
+			SPRUCE_PCI_CONFIG_ADDR,
+			SPRUCE_PCI_CONFIG_DATA);
+
+	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_map_irq = spruce_map_irq;
+}
+
+/*
+ * CPC700 PIC interrupt programming table
+ *
+ * First entry is the sensitivity (level/edge), second is the polarity.
+ */
+unsigned int cpc700_irq_assigns[32][2] = {
+	{ 1, 1 },       /* IRQ  0: ECC Correctable Error - rising edge */
+	{ 1, 1 },       /* IRQ  1: PCI Write Mem Range   - rising edge */
+	{ 0, 1 },       /* IRQ  2: PCI Write Command Reg - active high */
+	{ 0, 1 },       /* IRQ  3: UART 0                - active high */
+	{ 0, 1 },       /* IRQ  4: UART 1                - active high */
+	{ 0, 1 },       /* IRQ  5: ICC 0                 - active high */
+	{ 0, 1 },       /* IRQ  6: ICC 1                 - active high */
+	{ 0, 1 },       /* IRQ  7: GPT Compare 0         - active high */
+	{ 0, 1 },       /* IRQ  8: GPT Compare 1         - active high */
+	{ 0, 1 },       /* IRQ  9: GPT Compare 2         - active high */
+	{ 0, 1 },       /* IRQ 10: GPT Compare 3         - active high */
+	{ 0, 1 },       /* IRQ 11: GPT Compare 4         - active high */
+	{ 0, 1 },       /* IRQ 12: GPT Capture 0         - active high */
+	{ 0, 1 },       /* IRQ 13: GPT Capture 1         - active high */
+	{ 0, 1 },       /* IRQ 14: GPT Capture 2         - active high */
+	{ 0, 1 },       /* IRQ 15: GPT Capture 3         - active high */
+	{ 0, 1 },       /* IRQ 16: GPT Capture 4         - active high */
+	{ 0, 0 },       /* IRQ 17: Reserved */
+	{ 0, 0 },       /* IRQ 18: Reserved */
+	{ 0, 0 },       /* IRQ 19: Reserved */
+	{ 0, 1 },       /* IRQ 20: FPGA EXT_IRQ0         - active high */
+	{ 1, 1 },       /* IRQ 21: Mouse                 - rising edge */
+	{ 1, 1 },       /* IRQ 22: Keyboard              - rising edge */
+	{ 0, 0 },       /* IRQ 23: PCI Slot 3            - active low */
+	{ 0, 0 },       /* IRQ 24: PCI Slot 2            - active low */
+	{ 0, 0 },       /* IRQ 25: PCI Slot 1            - active low */
+	{ 0, 0 },       /* IRQ 26: PCI Slot 0            - active low */
+};
+
+static void __init
+spruce_calibrate_decr(void)
+{
+	int freq, divisor = 4;
+
+	/* determine processor bus speed */
+	freq = SPRUCE_BUS_SPEED;
+	tb_ticks_per_jiffy = freq / HZ / divisor;
+	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
+}
+
+static int
+spruce_show_cpuinfo(struct seq_file *m)
+{
+	seq_printf(m, "vendor\t\t: IBM\n");
+	seq_printf(m, "machine\t\t: Spruce\n");
+
+	return 0;
+}
+
+static void __init
+spruce_early_serial_map(void)
+{
+	u32 uart_clk;
+	struct uart_port serial_req;
+
+	if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))
+		uart_clk = SPRUCE_BAUD_33M * 16;
+	else
+		uart_clk = SPRUCE_BAUD_30M * 16;
+
+	/* Setup serial port access */
+	memset(&serial_req, 0, sizeof(serial_req));
+	serial_req.uartclk = uart_clk;
+	serial_req.irq = UART0_INT;
+	serial_req.flags = ASYNC_BOOT_AUTOCONF;
+	serial_req.iotype = SERIAL_IO_MEM;
+	serial_req.membase = (u_char *)UART0_IO_BASE;
+	serial_req.regshift = 0;
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
+	gen550_init(0, &serial_req);
+#endif
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 0 failed\n");
+#endif
+
+	/* Assume early_serial_setup() doesn't modify serial_req */
+	serial_req.line = 1;
+	serial_req.irq = UART1_INT;
+	serial_req.membase = (u_char *)UART1_IO_BASE;
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
+	gen550_init(1, &serial_req);
+#endif
+#ifdef CONFIG_SERIAL_8250
+	if (early_serial_setup(&serial_req) != 0)
+		printk("Early serial init of port 1 failed\n");
+#endif
+}
+
+TODC_ALLOC();
+
+static void __init
+spruce_setup_arch(void)
+{
+	/* Setup TODC access */
+	TODC_INIT(TODC_TYPE_DS1643, 0, 0, SPRUCE_RTC_BASE_ADDR, 8);
+
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000 / HZ;
+
+	/* Setup PCI host bridge */
+	spruce_setup_hose();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	if (initrd_start)
+		ROOT_DEV = Root_RAM0;
+	else
+#endif
+#ifdef CONFIG_ROOT_NFS
+		ROOT_DEV = Root_NFS;
+#else
+		ROOT_DEV = Root_SDA1;
+#endif
+
+#ifdef CONFIG_VT
+	conswitchp = &dummy_con;
+#endif
+
+
+	/* Identify the system */
+	printk(KERN_INFO "System Identification: IBM Spruce\n");
+	printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+}
+
+static void
+spruce_restart(char *cmd)
+{
+	local_irq_disable();
+
+	/* SRR0 has system reset vector, SRR1 has default MSR value */
+	/* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+	__asm__ __volatile__
+	("\n\
+	lis	3,0xfff0	\n\
+	ori	3,3,0x0100	\n\
+	mtspr	26,3		\n\
+	li	3,0		\n\
+	mtspr	27,3		\n\
+	rfi			\n\
+	");
+	for(;;);
+}
+
+static void
+spruce_power_off(void)
+{
+	for(;;);
+}
+
+static void
+spruce_halt(void)
+{
+	spruce_restart(NULL);
+}
+
+static void __init
+spruce_map_io(void)
+{
+	io_block_mapping(SPRUCE_PCI_IO_BASE, SPRUCE_PCI_PHY_IO_BASE,
+			 0x08000000, _PAGE_IO);
+}
+
+/*
+ * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
+ */
+static __inline__ void
+spruce_set_bat(void)
+{
+	mb();
+	mtspr(DBAT1U, 0xf8000ffe);
+	mtspr(DBAT1L, 0xf800002a);
+	mb();
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	/* Map in board regs, etc. */
+	spruce_set_bat();
+
+	isa_io_base = SPRUCE_ISA_IO_BASE;
+	pci_dram_offset = SPRUCE_PCI_SYS_MEM_BASE;
+
+	ppc_md.setup_arch = spruce_setup_arch;
+	ppc_md.show_cpuinfo = spruce_show_cpuinfo;
+	ppc_md.init_IRQ = cpc700_init_IRQ;
+	ppc_md.get_irq = cpc700_get_irq;
+
+	ppc_md.setup_io_mappings = spruce_map_io;
+
+	ppc_md.restart = spruce_restart;
+	ppc_md.power_off = spruce_power_off;
+	ppc_md.halt = spruce_halt;
+
+	ppc_md.time_init = todc_time_init;
+	ppc_md.set_rtc_time = todc_set_rtc_time;
+	ppc_md.get_rtc_time = todc_get_rtc_time;
+	ppc_md.calibrate_decr = spruce_calibrate_decr;
+
+	ppc_md.nvram_read_val = todc_direct_read_val;
+	ppc_md.nvram_write_val = todc_direct_write_val;
+
+	spruce_early_serial_map();
+
+#ifdef CONFIG_SERIAL_TEXT_DEBUG
+	ppc_md.progress = gen550_progress;
+#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#ifdef CONFIG_KGDB
+	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
+#endif
+}
diff -Nru a/arch/ppc/platforms/spruce.h b/arch/ppc/platforms/spruce.h
--- a/arch/ppc/platforms/spruce.h	Sat Apr  3 19:38:44 2004
+++ b/arch/ppc/platforms/spruce.h	Sat Apr  3 19:38:44 2004
@@ -57,10 +57,10 @@
 #define UART0_INT	3
 #define UART1_INT	4
 
-#define STD_UART_OP(num)				\
-	{ 0, BASE_BAUD, 0, UART##num##_INT,		\
-		ASYNC_BOOT_AUTOCONF,			\
-		iomem_base: UART##num##_IO_BASE,	\
+#define STD_UART_OP(num)						\
+	{ 0, BASE_BAUD, 0, UART##num##_INT,				\
+		ASYNC_BOOT_AUTOCONF,					\
+		iomem_base: (unsigned char *) UART##num##_IO_BASE,	\
 		io_type: SERIAL_IO_MEM},
 
 #define SERIAL_PORT_DFNS	\
diff -Nru a/arch/ppc/platforms/spruce_pci.c b/arch/ppc/platforms/spruce_pci.c
--- a/arch/ppc/platforms/spruce_pci.c	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,87 +0,0 @@
-/*
- * arch/ppc/platforms/spruce_pci.c
- *
- * PCI support for IBM Spruce
- *
- * Author: Johnnie Peters
- *         jpeters@mvista.com
- *
- * 2000 (c) 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <platforms/spruce.h>
-
-#include <syslib/cpc700.h>
-
-static inline int
-spruce_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-		/*
-		 * 	PCI IDSEL/INTPIN->INTLINE
-		 * 	A	B	C	D
-		 */
-	{
-		{23, 24, 25, 26},	/* IDSEL 1 - PCI slot 3 */
-		{24, 25, 26, 23},	/* IDSEL 2 - PCI slot 2 */
-		{25, 26, 23, 24},	/* IDSEL 3 - PCI slot 1 */
-		{26, 23, 24, 25},	/* IDSEL 4 - PCI slot 0 */
-	};
-
-	const long min_idsel = 1, max_idsel = 4, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-}
-
-void __init
-spruce_setup_hose(void)
-{
-	struct pci_controller *hose;
-
-	/* Setup hose */
-	hose = pcibios_alloc_controller();
-	if (!hose)
-		return;
-
-	hose->first_busno = 0;
-	hose->last_busno = 0xff;
-
-	pci_init_resource(&hose->io_resource,
-			SPRUCE_PCI_LOWER_IO,
-			SPRUCE_PCI_UPPER_IO,
-			IORESOURCE_IO,
-			"PCI host bridge");
-
-	pci_init_resource(&hose->mem_resources[0],
-			SPRUCE_PCI_LOWER_MEM,
-			SPRUCE_PCI_UPPER_MEM,
-			IORESOURCE_MEM,
-			"PCI host bridge");
-
-	hose->io_space.start = SPRUCE_PCI_LOWER_IO;
-	hose->io_space.end = SPRUCE_PCI_UPPER_IO;
-	hose->mem_space.start = SPRUCE_PCI_LOWER_MEM;
-	hose->mem_space.end = SPRUCE_PCI_UPPER_MEM;
-	hose->io_base_virt = (void *)SPRUCE_ISA_IO_BASE;
-
-	setup_indirect_pci(hose,
-			SPRUCE_PCI_CONFIG_ADDR,
-			SPRUCE_PCI_CONFIG_DATA);
-
-	hose->last_busno = pciauto_bus_scan(hose, hose->first_busno);
-
-	ppc_md.pci_swizzle = common_swizzle;
-	ppc_md.pci_map_irq = spruce_map_irq;
-}
diff -Nru a/arch/ppc/platforms/spruce_serial.h b/arch/ppc/platforms/spruce_serial.h
--- a/arch/ppc/platforms/spruce_serial.h	Sat Apr  3 19:38:56 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-/*
- * include/asm-ppc/spruce_serial.h
- *
- * Definitions for IBM Spruce reference board support
- *
- * Authors: Matt Porter and Johnnie Peters
- *          mporter@mvista.com
- *          jpeters@mvista.com
- *
- * 2000 (c) 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.
- */
-
-#ifndef __ASMPPC_SPRUCE_SERIAL_H
-#define __ASMPPC_SPRUCE_SERIAL_H
-
-#include <linux/config.h>
-
-/* This is where the serial ports exist */
-#define SPRUCE_SERIAL_1_ADDR	0xff600300
-#define SPRUCE_SERIAL_2_ADDR	0xff600400
-
-#define RS_TABLE_SIZE  4
-
-/* Rate for the baud clock for the onboard serial chip */
-#ifndef CONFIG_SPRUCE_BAUD_33M
-#define BASE_BAUD  (30000000 / 4 / 16)
-#else
-#define BASE_BAUD  (33000000 / 4 / 16)
-#endif
-
-#ifndef SERIAL_MAGIC_KEY
-#define kernel_debugger ppc_kernel_debug
-#endif
-
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
-#endif
-
-#define STD_SERIAL_PORT_DFNS \
-        { 0, BASE_BAUD, SPRUCE_SERIAL_1_ADDR, 3, STD_COM_FLAGS,	/* ttyS0 */ \
-		iomem_base: (u8 *)SPRUCE_SERIAL_1_ADDR,			    \
-		io_type: SERIAL_IO_MEM },				    \
-        { 0, BASE_BAUD, SPRUCE_SERIAL_2_ADDR, 4, STD_COM_FLAGS,	/* ttyS1 */ \
-		iomem_base: (u8 *)SPRUCE_SERIAL_2_ADDR,			    \
-		io_type: SERIAL_IO_MEM },
-
-#define SERIAL_PORT_DFNS \
-        STD_SERIAL_PORT_DFNS
-
-#endif /* __ASMPPC_SPRUCE_SERIAL_H */
diff -Nru a/arch/ppc/platforms/spruce_setup.c b/arch/ppc/platforms/spruce_setup.c
--- a/arch/ppc/platforms/spruce_setup.c	Sat Apr  3 19:38:41 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,276 +0,0 @@
-/*
- * arch/ppc/platforms/spruce_setup.c
- *
- * Board setup routines for IBM Spruce
- *
- * Authors: Johnnie Peters <jpeters@mvista.com>
- *          Matt Porter <mporter@mvista.com>
- *
- * 2001-2002 (c) 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.
- */
-
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/reboot.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/types.h>
-#include <linux/major.h>
-#include <linux/initrd.h>
-#include <linux/console.h>
-#include <linux/delay.h>
-#include <linux/seq_file.h>
-#include <linux/ide.h>
-#include <linux/root_dev.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/machdep.h>
-#include <asm/time.h>
-#include <platforms/spruce.h>
-#include <asm/todc.h>
-#include <asm/bootinfo.h>
-#include <asm/kgdb.h>
-
-#include <syslib/cpc700.h>
-
-extern void spruce_init_IRQ(void);
-extern int spruce_get_irq(struct pt_regs *);
-extern void spruce_setup_hose(void);
-
-extern char cmd_line[];
-
-/*
- * CPC700 PIC interrupt programming table
- *
- * First entry is the sensitivity (level/edge), second is the polarity.
- */
-unsigned int cpc700_irq_assigns[32][2] = {
-	{ 1, 1 },       /* IRQ  0: ECC Correctable Error - rising edge */
-	{ 1, 1 },       /* IRQ  1: PCI Write Mem Range   - rising edge */
-	{ 0, 1 },       /* IRQ  2: PCI Write Command Reg - active high */
-	{ 0, 1 },       /* IRQ  3: UART 0                - active high */
-	{ 0, 1 },       /* IRQ  4: UART 1                - active high */
-	{ 0, 1 },       /* IRQ  5: ICC 0                 - active high */
-	{ 0, 1 },       /* IRQ  6: ICC 1                 - active high */
-	{ 0, 1 },       /* IRQ  7: GPT Compare 0         - active high */
-	{ 0, 1 },       /* IRQ  8: GPT Compare 1         - active high */
-	{ 0, 1 },       /* IRQ  9: GPT Compare 2         - active high */
-	{ 0, 1 },       /* IRQ 10: GPT Compare 3         - active high */
-	{ 0, 1 },       /* IRQ 11: GPT Compare 4         - active high */
-	{ 0, 1 },       /* IRQ 12: GPT Capture 0         - active high */
-	{ 0, 1 },       /* IRQ 13: GPT Capture 1         - active high */
-	{ 0, 1 },       /* IRQ 14: GPT Capture 2         - active high */
-	{ 0, 1 },       /* IRQ 15: GPT Capture 3         - active high */
-	{ 0, 1 },       /* IRQ 16: GPT Capture 4         - active high */
-	{ 0, 0 },       /* IRQ 17: Reserved */
-	{ 0, 0 },       /* IRQ 18: Reserved */
-	{ 0, 0 },       /* IRQ 19: Reserved */
-	{ 0, 1 },       /* IRQ 20: FPGA EXT_IRQ0         - active high */
-	{ 1, 1 },       /* IRQ 21: Mouse                 - rising edge */
-	{ 1, 1 },       /* IRQ 22: Keyboard              - rising edge */
-	{ 0, 0 },       /* IRQ 23: PCI Slot 3            - active low */
-	{ 0, 0 },       /* IRQ 24: PCI Slot 2            - active low */
-	{ 0, 0 },       /* IRQ 25: PCI Slot 1            - active low */
-	{ 0, 0 },       /* IRQ 26: PCI Slot 0            - active low */
-};
-
-static void __init
-spruce_calibrate_decr(void)
-{
-	int freq, divisor = 4;
-
-	/* determine processor bus speed */
-	freq = SPRUCE_BUS_SPEED;
-	tb_ticks_per_jiffy = freq / HZ / divisor;
-	tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000);
-}
-
-static int
-spruce_show_cpuinfo(struct seq_file *m)
-{
-	seq_printf(m, "vendor\t\t: IBM\n");
-	seq_printf(m, "machine\t\t: Spruce\n");
-
-	return 0;
-}
-
-static void __init
-spruce_early_serial_map(void)
-{
-	u32 uart_clk;
-	struct uart_port serial_req;
-
-	if (SPRUCE_UARTCLK_IS_33M(readb(SPRUCE_FPGA_REG_A)))
-		uart_clk = SPRUCE_BAUD_33M * 16;
-	else
-		uart_clk = SPRUCE_BAUD_30M * 16;
-
-	/* Setup serial port access */
-	memset(&serial_req, 0, sizeof(serial_req));
-	serial_req.uartclk = uart_clk;
-	serial_req.irq = UART0_INT;
-	serial_req.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
-	serial_req.iotype = SERIAL_IO_MEM;
-	serial_req.membase = (u_char *)UART0_IO_BASE;
-	serial_req.regshift = 0;
-
-#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
-	gen550_init(0, &serial_req);
-#endif
-#ifdef CONFIG_SERIAL_8250
-	if (early_serial_setup(&serial_req) != 0)
-		printk("Early serial init of port 0 failed\n");
-#endif
-
-	/* Assume early_serial_setup() doesn't modify serial_req */
-	serial_req.line = 1;
-	serial_req.irq = UART1_INT;
-	serial_req.membase = (u_char *)UART1_IO_BASE;
-
-#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG)
-	gen550_init(1, &serial_req);
-#endif
-#ifdef CONFIG_SERIAL_8250
-	if (early_serial_setup(&serial_req) != 0)
-		printk("Early serial init of port 1 failed\n");
-#endif
-}
-
-TODC_ALLOC();
-
-static void __init
-spruce_setup_arch(void)
-{
-	/* Setup TODC access */
-	TODC_INIT(TODC_TYPE_DS1643, 0, 0, SPRUCE_RTC_BASE_ADDR, 8);
-
-	/* init to some ~sane value until calibrate_delay() runs */
-	loops_per_jiffy = 50000000 / HZ;
-
-	/* Setup PCI host bridge */
-	spruce_setup_hose();
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	if (initrd_start)
-		ROOT_DEV = Root_RAM0;
-	else
-#endif
-#ifdef CONFIG_ROOT_NFS
-		ROOT_DEV = Root_NFS;
-#else
-		ROOT_DEV = Root_SDA1;
-#endif
-
-#ifdef CONFIG_VT
-	conswitchp = &dummy_con;
-#endif
-
-
-	/* Identify the system */
-	printk(KERN_INFO "System Identification: IBM Spruce\n");
-	printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
-}
-
-static void
-spruce_restart(char *cmd)
-{
-	local_irq_disable();
-
-	/* SRR0 has system reset vector, SRR1 has default MSR value */
-	/* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
-	__asm__ __volatile__
-	("\n\
-	lis	3,0xfff0	\n\
-	ori	3,3,0x0100	\n\
-	mtspr	26,3		\n\
-	li	3,0		\n\
-	mtspr	27,3		\n\
-	rfi			\n\
-	");
-	for(;;);
-}
-
-static void
-spruce_power_off(void)
-{
-	for(;;);
-}
-
-static void
-spruce_halt(void)
-{
-	spruce_restart(NULL);
-}
-
-static void __init
-spruce_map_io(void)
-{
-	io_block_mapping(SPRUCE_PCI_IO_BASE, SPRUCE_PCI_PHY_IO_BASE,
-			 0x08000000, _PAGE_IO);
-}
-
-/*
- * Set BAT 3 to map 0xf8000000 to end of physical memory space 1-to-1.
- */
-static __inline__ void
-spruce_set_bat(void)
-{
-	mb();
-	mtspr(DBAT1U, 0xf8000ffe);
-	mtspr(DBAT1L, 0xf800002a);
-	mb();
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	      unsigned long r6, unsigned long r7)
-{
-	parse_bootinfo(find_bootinfo());
-
-	/* Map in board regs, etc. */
-	spruce_set_bat();
-
-	isa_io_base = SPRUCE_ISA_IO_BASE;
-	pci_dram_offset = SPRUCE_PCI_SYS_MEM_BASE;
-
-	ppc_md.setup_arch = spruce_setup_arch;
-	ppc_md.show_cpuinfo = spruce_show_cpuinfo;
-	ppc_md.init_IRQ = cpc700_init_IRQ;
-	ppc_md.get_irq = cpc700_get_irq;
-
-	ppc_md.setup_io_mappings = spruce_map_io;
-
-	ppc_md.restart = spruce_restart;
-	ppc_md.power_off = spruce_power_off;
-	ppc_md.halt = spruce_halt;
-
-	ppc_md.time_init = todc_time_init;
-	ppc_md.set_rtc_time = todc_set_rtc_time;
-	ppc_md.get_rtc_time = todc_get_rtc_time;
-	ppc_md.calibrate_decr = spruce_calibrate_decr;
-
-	ppc_md.nvram_read_val = todc_direct_read_val;
-	ppc_md.nvram_write_val = todc_direct_write_val;
-
-	spruce_early_serial_map();
-
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
-	ppc_md.progress = gen550_progress;
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
-#ifdef CONFIG_KGDB
-	ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
-#endif
-}
diff -Nru a/arch/ppc/syslib/gen550_dbg.c b/arch/ppc/syslib/gen550_dbg.c
--- a/arch/ppc/syslib/gen550_dbg.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/syslib/gen550_dbg.c	Sat Apr  3 19:38:43 2004
@@ -151,7 +151,7 @@
 gen550_init(int i, struct uart_port *serial_req)
 {
 	rs_table[i].io_type = serial_req->iotype;
-	rs_table[i].port = serial_req->line;
+	rs_table[i].port = serial_req->iobase;
 	rs_table[i].iomem_base = serial_req->membase;
 	rs_table[i].iomem_reg_shift = serial_req->regshift;
 }
diff -Nru a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c
--- a/arch/ppc/syslib/indirect_pci.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc/syslib/indirect_pci.c	Sat Apr  3 19:38:41 2004
@@ -21,6 +21,12 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 
+#ifdef CONFIG_PPC_INDIRECT_PCI_BE
+#define PCI_CFG_OUT out_be32
+#else
+#define PCI_CFG_OUT out_le32
+#endif
+
 static int
 indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
 		     int len, u32 *val)
@@ -37,9 +43,10 @@
 		if (bus->number != hose->first_busno)
 			cfg_type = 1;
 
-	out_be32(hose->cfg_addr,
-		 (((offset & 0xfc) | cfg_type) << 24) | (devfn << 16)
-		 | ((bus->number - hose->bus_offset) << 8) | 0x80);
+	PCI_CFG_OUT(hose->cfg_addr, 					 
+		 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
+		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+
 	/*
 	 * Note: the caller has already checked that offset is
 	 * suitably aligned and that len is 1, 2 or 4.
@@ -75,9 +82,10 @@
 		if (bus->number != hose->first_busno)
 			cfg_type = 1;
 
-	out_be32(hose->cfg_addr,
-		 (((offset & 0xfc) | cfg_type) << 24) | (devfn << 16)
-		 | ((bus->number - hose->bus_offset) << 8) | 0x80);
+	PCI_CFG_OUT(hose->cfg_addr, 					 
+		 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
+		  | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+
 	/*
 	 * Note: the caller has already checked that offset is
 	 * suitably aligned and that len is 1, 2 or 4.
diff -Nru a/arch/ppc/syslib/pplus_common.c b/arch/ppc/syslib/pplus_common.c
--- a/arch/ppc/syslib/pplus_common.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc/syslib/pplus_common.c	Sat Apr  3 19:38:43 2004
@@ -21,7 +21,7 @@
 #include <asm/pci.h>
 #include <asm/pci-bridge.h>
 #include <asm/open_pic.h>
-#include <asm/pplus.h>
+#include <asm/hawk.h>
 
 /*
  * The Falcon/Raven and HAWK has 4 sets of registers:
@@ -95,10 +95,10 @@
 	/*
 	 * Disable previous PPC->PCI mappings.
 	 */
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), 0x00000000);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), 0x00000000);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF2_OFF), 0x00000000);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF3_OFF), 0x00000000);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF0_OFF), 0x00000000);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF1_OFF), 0x00000000);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF2_OFF), 0x00000000);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF3_OFF), 0x00000000);
 
 	/*
 	 * Program the XSADD/XSOFF registers to set up the PCI Mem & I/O
@@ -113,21 +113,23 @@
 	/* Set up PPC->PCI Mem mapping */
 	addr = processor_pci_mem_start | (processor_pci_mem_end >> 16);
 	offset = (hose->mem_space.start - processor_pci_mem_start) | 0xd2;
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD0_OFF), addr);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), offset);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSADD0_OFF), addr);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF0_OFF), offset);
 
 	/* Set up PPC->MPIC mapping on the bridge */
 	addr = processor_mpic_base |
-	        (((processor_mpic_base + PPLUS_MPIC_SIZE) >> 16) - 1);
-	offset = 0xc2; /* No write posting for this PCI Mem space */
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD1_OFF), addr);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), offset);
+	        (((processor_mpic_base + HAWK_MPIC_SIZE) >> 16) - 1);
+	/* No write posting for this PCI Mem space */
+	offset = (hose->mem_space.start - processor_pci_mem_start) | 0xc2;
+
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSADD1_OFF), addr);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF1_OFF), offset);
 
 	/* Set up PPC->PCI I/O mapping -- Contiguous I/O space */
 	addr = processor_pci_io_start | (processor_pci_io_end >> 16);
 	offset = (hose->io_space.start - processor_pci_io_start) | 0xc0;
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD3_OFF), addr);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF3_OFF), offset);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSADD3_OFF), addr);
+	out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF3_OFF), offset);
 
 	hose->io_base_virt = (void *)ioremap(processor_pci_io_start,
 			(processor_pci_io_end - processor_pci_io_start + 1));
@@ -137,8 +139,8 @@
 	 * The PCI config addr/data pair based on start addr of PCI I/O space.
 	 */
 	setup_indirect_pci(hose,
-			   processor_pci_io_start + PPLUS_PCI_CONFIG_ADDR_OFF,
-			   processor_pci_io_start + PPLUS_PCI_CONFIG_DATA_OFF);
+			   processor_pci_io_start + HAWK_PCI_CONFIG_ADDR_OFF,
+			   processor_pci_io_start + HAWK_PCI_CONFIG_DATA_OFF);
 
 	/*
 	 * Disable previous PCI->PPC mappings.
@@ -161,10 +163,12 @@
 			         0,
 			         PCI_DEVFN(0,0),
 			         PCI_BASE_ADDRESS_1,
-			         processor_mpic_base | 0x0);
+			         (processor_mpic_base -
+				 processor_pci_mem_start + 
+				 hose->mem_space.start) | 0x0);
 
 	/* Map MPIC into vitual memory */
-	OpenPIC_Addr = ioremap(processor_mpic_base, PPLUS_MPIC_SIZE);
+	OpenPIC_Addr = ioremap(processor_mpic_base, HAWK_MPIC_SIZE);
 
 	return 0;
 }
@@ -181,14 +185,14 @@
 #define	MB	(1024*1024)
 
 static uint reg_offset_table[] __initdata = {
-	PPLUS_SMC_RAM_A_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_B_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_C_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_D_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_E_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_F_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_G_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_H_SIZE_REG_OFF
+	HAWK_SMC_RAM_A_SIZE_REG_OFF,
+	HAWK_SMC_RAM_B_SIZE_REG_OFF,
+	HAWK_SMC_RAM_C_SIZE_REG_OFF,
+	HAWK_SMC_RAM_D_SIZE_REG_OFF,
+	HAWK_SMC_RAM_E_SIZE_REG_OFF,
+	HAWK_SMC_RAM_F_SIZE_REG_OFF,
+	HAWK_SMC_RAM_G_SIZE_REG_OFF,
+	HAWK_SMC_RAM_H_SIZE_REG_OFF
 };
 
 static uint falcon_size_table[] __initdata = {
@@ -246,13 +250,13 @@
 		size_table_entries = sizeof(falcon_size_table) /
 				     sizeof(falcon_size_table[0]);
 
-		reg_limit = PPLUS_FALCON_SMC_REG_COUNT;
+		reg_limit = FALCON_SMC_REG_COUNT;
 	}
 	else if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HAWK) {
 		size_table = hawk_size_table;
 		size_table_entries = sizeof(hawk_size_table) /
 				     sizeof(hawk_size_table[0]);
-		reg_limit = PPLUS_HAWK_SMC_REG_COUNT;
+		reg_limit = HAWK_SMC_REG_COUNT;
 	}
 	else {
 		printk("pplus_get_mem_size: %s (0x%x)\n",
diff -Nru a/arch/ppc/syslib/todc_time.c b/arch/ppc/syslib/todc_time.c
--- a/arch/ppc/syslib/todc_time.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc/syslib/todc_time.c	Sat Apr  3 19:38:54 2004
@@ -7,7 +7,7 @@
  * Author: Mark A. Greer
  *         mgreer@mvista.com
  *
- * 2001 (c) MontaVista, Software, Inc.  This file is licensed under
+ * 2001-2004 (c) 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.
@@ -31,15 +31,13 @@
  * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and
  * 'nvram_as1' NULL.  If your board uses address/data regs to access nvram,
  * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the
- * address of the upper byte (leave NULL if using mv146818), and set
+ * address of the upper byte (leave NULL if using mc146818), and set
  * 'nvram_data' to the address of the 8-bit data register.
  *
- * You also need to set 'ppc_md.nvram_read_val' and 'ppc_md.nvram_write_val' to
- * the proper routines.  There are standard ones defined further down in
- * this file that you can use.
- *
- * There is a built in assumption that the RTC and NVRAM are accessed by the
- * same mechanism (i.e., ppc_md.nvram_read_val, etc works for both).
+ * In order to break the assumption that the RTC and NVRAM are accessed by
+ * the same mechanism, you need to explicitly set 'ppc_md.rtc_read_val' and
+ * 'ppc_md.rtc_write_val', otherwise the values of 'ppc_md.rtc_read_val'
+ * and 'ppc_md.rtc_write_val' will be used.
  *
  * Note: Even though the documentation for the various RTC chips say that it
  * 	 take up to a second before it starts updating once the 'R' bit is
@@ -50,6 +48,8 @@
  * 	 					--MAG
  */
 
+extern spinlock_t	rtc_lock;
+
 /*
  * 'todc_info' should be initialized in your *_setup.c file to
  * point to a fully initialized 'todc_info_t' structure.
@@ -114,16 +114,63 @@
 u_char
 todc_mc146818_read_val(int addr)
 {
-	outb(addr, todc_info->nvram_as0);
-	return inb(todc_info->nvram_data);
+	outb_p(addr, todc_info->nvram_as0);
+	return inb_p(todc_info->nvram_data);
 }
 
 void
 todc_mc146818_write_val(int addr, unsigned char val)
 {
-	outb(addr, todc_info->nvram_as0);
-   	outb(val, todc_info->nvram_data);
-	return;
+	outb_p(addr, todc_info->nvram_as0);
+   	outb_p(val, todc_info->nvram_data);
+}
+
+
+/*
+ * Routines to make RTC chips with NVRAM buried behind an addr/data pair
+ * have the NVRAM and clock regs appear at the same level.
+ * The NVRAM will appear to start at addr 0 and the clock regs will appear
+ * to start immediately after the NVRAM (actually, start at offset
+ * todc_info->nvram_size).
+ */
+static inline u_char
+todc_read_val(int addr)
+{
+	u_char	val;
+
+	if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
+		if (addr < todc_info->nvram_size) { /* NVRAM */
+			ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr);
+			val = ppc_md.rtc_read_val(todc_info->nvram_data_reg);
+		}
+		else { /* Clock Reg */
+			addr -= todc_info->nvram_size;
+			val = ppc_md.rtc_read_val(addr);
+		}
+	}
+	else {
+		val = ppc_md.rtc_read_val(addr);
+	}
+
+	return val;
+}
+
+static inline void
+todc_write_val(int addr, u_char val)
+{
+	if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
+		if (addr < todc_info->nvram_size) { /* NVRAM */
+			ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr);
+			ppc_md.rtc_write_val(todc_info->nvram_data_reg, val);
+		}
+		else { /* Clock Reg */
+			addr -= todc_info->nvram_size;
+			ppc_md.rtc_write_val(addr, val);
+		}
+	}
+	else {
+		ppc_md.rtc_write_val(addr, val);
+	}
 }
 
 /*
@@ -142,77 +189,80 @@
 long __init
 todc_time_init(void)
 {
-	static u_char	not_initialized = 1;
-
-	/* Make sure clocks are running */
-	if (not_initialized) {
-		u_char	cntl_b;
+	u_char	cntl_b;
 
-		cntl_b = ppc_md.nvram_read_val(todc_info->control_b);
+	if (!ppc_md.rtc_read_val)
+		ppc_md.rtc_read_val = ppc_md.nvram_read_val;
+	if (!ppc_md.rtc_write_val)
+		ppc_md.rtc_write_val = ppc_md.nvram_write_val;
+	
+	cntl_b = todc_read_val(todc_info->control_b);
 
-		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-			if ((cntl_b & 0x70) != 0x20) {
-				printk(KERN_INFO "TODC %s %s\n",
-					"real-time-clock was stopped.",
-					"Now starting...");
-				cntl_b &= ~0x70;
-				cntl_b |= 0x20;
-			}
-
-			ppc_md.nvram_write_val(todc_info->control_b, cntl_b);
+	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+		if ((cntl_b & 0x70) != 0x20) {
+			printk(KERN_INFO "TODC %s %s\n",
+				"real-time-clock was stopped.",
+				"Now starting...");
+			cntl_b &= ~0x70;
+			cntl_b |= 0x20;
 		}
-		else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
-			u_char	month;
-
-			todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
-			todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
-
-			month = ppc_md.nvram_read_val(todc_info->month);
 
-			if ((month & 0x80) == 0x80) {
-				printk(KERN_INFO "TODC %s %s\n",
-					"real-time-clock was stopped.",
-					"Now starting...");
-				month &= ~0x80;
-				ppc_md.nvram_write_val(todc_info->month, month);
-			}
-
-			cntl_b &= ~TODC_DS1501_CNTL_B_TE;
-			ppc_md.nvram_write_val(todc_info->control_b, cntl_b);
+		todc_write_val(todc_info->control_b, cntl_b);
+	} else if (todc_info->rtc_type == TODC_TYPE_DS17285) {
+		u_char mode;
+
+		mode = todc_read_val(TODC_TYPE_DS17285_CNTL_A);
+		/* Make sure countdown clear is not set */
+		mode &= ~0x40;
+		/* Enable oscillator, extended register set */
+		mode |= 0x30;
+		todc_write_val(TODC_TYPE_DS17285_CNTL_A, mode);
+
+	} else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
+		u_char	month;
+
+		todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
+		todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
+
+		month = todc_read_val(todc_info->month);
+
+		if ((month & 0x80) == 0x80) {
+			printk(KERN_INFO "TODC %s %s\n",
+				"real-time-clock was stopped.",
+				"Now starting...");
+			month &= ~0x80;
+			todc_write_val(todc_info->month, month);
 		}
-		else { /* must be a m48txx type */
-			u_char	cntl_a;
-
-			todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
-			todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
-
-			cntl_a = ppc_md.nvram_read_val(todc_info->control_a);
 
-			/* Check & clear STOP bit in control B register */
-			if (cntl_b & TODC_MK48TXX_DAY_CB) {
-				printk(KERN_INFO "TODC %s %s\n",
-					"real-time-clock was stopped.",
-					"Now starting...");
+		cntl_b &= ~TODC_DS1501_CNTL_B_TE;
+		todc_write_val(todc_info->control_b, cntl_b);
+	} else { /* must be a m48txx type */
+		u_char	cntl_a;
+
+		todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
+		todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
+
+		cntl_a = todc_read_val(todc_info->control_a);
+
+		/* Check & clear STOP bit in control B register */
+		if (cntl_b & TODC_MK48TXX_DAY_CB) {
+			printk(KERN_INFO "TODC %s %s\n",
+				"real-time-clock was stopped.",
+				"Now starting...");
 
-				cntl_a |= todc_info->enable_write;
-				cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */
+			cntl_a |= todc_info->enable_write;
+			cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */
 
-				ppc_md.nvram_write_val(todc_info->control_a,
-						       cntl_a);
-				ppc_md.nvram_write_val(todc_info->control_b,
-						       cntl_b);
-			}
-
-			/* Make sure READ & WRITE bits are cleared. */
-			cntl_a &= ~(todc_info->enable_write |
-				    todc_info->enable_read);
-			ppc_md.nvram_write_val(todc_info->control_a, cntl_a);
+			todc_write_val(todc_info->control_a, cntl_a);
+			todc_write_val(todc_info->control_b, cntl_b);
 		}
 
-		not_initialized = 0;
+		/* Make sure READ & WRITE bits are cleared. */
+		cntl_a &= ~(todc_info->enable_write |
+			    todc_info->enable_read);
+		todc_write_val(todc_info->control_a, cntl_a);
 	}
 
-
 	return 0;
 }
 
@@ -231,7 +281,8 @@
 	uint	limit, i;
 	u_char	save_control, uip;
 
-	save_control = ppc_md.nvram_read_val(todc_info->control_a);
+	spin_lock(&rtc_lock);
+	save_control = todc_read_val(todc_info->control_a);
 
 	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
 		limit = 1;
@@ -241,9 +292,10 @@
 			case TODC_TYPE_DS1743:
 			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
 			case TODC_TYPE_DS1747:
+			case TODC_TYPE_DS17285:
 				break;
 			default:
-				ppc_md.nvram_write_val(todc_info->control_a,
+				todc_write_val(todc_info->control_a,
 				       (save_control | todc_info->enable_read));
 		}
 	}
@@ -253,19 +305,18 @@
 
 	for (i=0; i<limit; i++) {
 		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-			uip = ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT);
+			uip = todc_read_val(todc_info->RTC_FREQ_SELECT);
 		}
 
-		sec = ppc_md.nvram_read_val(todc_info->seconds) & 0x7f;
-		min = ppc_md.nvram_read_val(todc_info->minutes) & 0x7f;
-		hour = ppc_md.nvram_read_val(todc_info->hours) & 0x3f;
-		day = ppc_md.nvram_read_val(todc_info->day_of_month) & 0x3f;
-		mon = ppc_md.nvram_read_val(todc_info->month) & 0x1f;
-		year = ppc_md.nvram_read_val(todc_info->year) & 0xff;
+		sec = todc_read_val(todc_info->seconds) & 0x7f;
+		min = todc_read_val(todc_info->minutes) & 0x7f;
+		hour = todc_read_val(todc_info->hours) & 0x3f;
+		day = todc_read_val(todc_info->day_of_month) & 0x3f;
+		mon = todc_read_val(todc_info->month) & 0x1f;
+		year = todc_read_val(todc_info->year) & 0xff;
 
 		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-			uip |= ppc_md.nvram_read_val(
-					todc_info->RTC_FREQ_SELECT);
+			uip |= todc_read_val(todc_info->RTC_FREQ_SELECT);
 			if ((uip & RTC_UIP) == 0) break;
 		}
 	}
@@ -276,13 +327,15 @@
 			case TODC_TYPE_DS1743:
 			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
 			case TODC_TYPE_DS1747:
+			case TODC_TYPE_DS17285:
 				break;
 			default:
 				save_control &= ~(todc_info->enable_read);
-				ppc_md.nvram_write_val(todc_info->control_a,
+				todc_write_val(todc_info->control_a,
 						       save_control);
 		}
 	}
+	spin_unlock(&rtc_lock);
 
 	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
 	    ((save_control & RTC_DM_BINARY) == 0) ||
@@ -310,19 +363,19 @@
 	struct rtc_time	tm;
 	u_char		save_control, save_freq_select;
 
+	spin_lock(&rtc_lock);
 	to_tm(nowtime, &tm);
 
-	save_control = ppc_md.nvram_read_val(todc_info->control_a);
+	save_control = todc_read_val(todc_info->control_a);
 
 	/* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */
-	ppc_md.nvram_write_val(todc_info->control_a,
+	todc_write_val(todc_info->control_a,
 			       (save_control | todc_info->enable_write));
 	save_control &= ~(todc_info->enable_write); /* in case it was set */
 
 	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-		save_freq_select =
-			ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT);
-		ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT,
+		save_freq_select = todc_read_val(todc_info->RTC_FREQ_SELECT);
+		todc_write_val(todc_info->RTC_FREQ_SELECT,
 				       save_freq_select | RTC_DIV_RESET2);
 	}
 
@@ -341,19 +394,19 @@
 		BIN_TO_BCD(tm.tm_year);
 	}
 
-	ppc_md.nvram_write_val(todc_info->seconds,      tm.tm_sec);
-	ppc_md.nvram_write_val(todc_info->minutes,      tm.tm_min);
-	ppc_md.nvram_write_val(todc_info->hours,        tm.tm_hour);
-	ppc_md.nvram_write_val(todc_info->month,        tm.tm_mon);
-	ppc_md.nvram_write_val(todc_info->day_of_month, tm.tm_mday);
-	ppc_md.nvram_write_val(todc_info->year,         tm.tm_year);
+	todc_write_val(todc_info->seconds,      tm.tm_sec);
+	todc_write_val(todc_info->minutes,      tm.tm_min);
+	todc_write_val(todc_info->hours,        tm.tm_hour);
+	todc_write_val(todc_info->month,        tm.tm_mon);
+	todc_write_val(todc_info->day_of_month, tm.tm_mday);
+	todc_write_val(todc_info->year,         tm.tm_year);
 
-	ppc_md.nvram_write_val(todc_info->control_a, save_control);
+	todc_write_val(todc_info->control_a, save_control);
 
 	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-		ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT,
-				       save_freq_select);
+		todc_write_val(todc_info->RTC_FREQ_SELECT, save_freq_select);
 	}
+	spin_unlock(&rtc_lock);
 
 	return 0;
 }
@@ -367,30 +420,28 @@
 
 	switch (todc_info->rtc_type) {
 		case TODC_TYPE_DS1557:
-		case TODC_TYPE_DS1743:
 		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
 		case TODC_TYPE_DS1747:
+		case TODC_TYPE_DS17285:
 		case TODC_TYPE_MC146818:
 			break;
 		default:
-			save_control =
-				ppc_md.nvram_read_val(todc_info->control_a);
-			ppc_md.nvram_write_val(todc_info->control_a,
+			save_control = todc_read_val(todc_info->control_a);
+			todc_write_val(todc_info->control_a,
 				       (save_control | todc_info->enable_read));
 	}
-	val = ppc_md.nvram_read_val(addr);
+	val = todc_read_val(addr);
 
 	switch (todc_info->rtc_type) {
 		case TODC_TYPE_DS1557:
-		case TODC_TYPE_DS1743:
 		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
 		case TODC_TYPE_DS1747:
+		case TODC_TYPE_DS17285:
 		case TODC_TYPE_MC146818:
 			break;
 		default:
 			save_control &= ~(todc_info->enable_read);
-			ppc_md.nvram_write_val(todc_info->control_a,
-					       save_control);
+			todc_write_val(todc_info->control_a, save_control);
 	}
 
 	return val;
@@ -412,7 +463,7 @@
 
 	/*
 	 * Actually this is bad for precision, we should have a loop in
-	 * which we only read the seconds counter. nvram_read_val writes
+	 * which we only read the seconds counter. todc_read_val writes
 	 * the address bytes on every call and this takes a lot of time.
 	 * Perhaps an nvram_wait_change method returning a time
 	 * stamp with a loop count as parameter would be the solution.
diff -Nru a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
--- a/arch/ppc64/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/Kconfig	Sat Apr  3 19:38:43 2004
@@ -174,14 +174,12 @@
 	depends on DISCONTIGMEM
 
 config PREEMPT
-	bool
+	bool "Preemptible Kernel"
+	depends on BROKEN
 	help
 	  This option reduces the latency of the kernel when reacting to
 	  real-time or interactive events by allowing a low priority process to
 	  be preempted even if it is in kernel mode executing a system call.
-	  Unfortunately the kernel code has some race conditions if both
-	  CONFIG_SMP and CONFIG_PREEMPT are enabled, so this option is
-	  currently disabled if you are building an SMP kernel.
 
 	  Say Y here if you are building a kernel for a desktop, embedded
 	  or real-time system.  Say N if you are unsure.
diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile
--- a/arch/ppc64/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/Makefile	Sat Apr  3 19:38:41 2004
@@ -53,7 +53,7 @@
 	$(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 -Nru a/arch/ppc64/configs/g5_defconfig b/arch/ppc64/configs/g5_defconfig
--- a/arch/ppc64/configs/g5_defconfig	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/configs/g5_defconfig	Sat Apr  3 19:38:41 2004
@@ -46,6 +46,7 @@
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_KMOD is not set
+CONFIG_STOP_MACHINE=y
 
 #
 # Platform support
@@ -100,6 +101,7 @@
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -126,10 +128,10 @@
 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=8192
 CONFIG_BLK_DEV_INITRD=y
-# CONFIG_DCSSBLK is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -193,7 +195,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -221,6 +222,12 @@
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
@@ -236,6 +243,7 @@
 # CONFIG_SCSI_ATA_PIIX is not set
 # CONFIG_SCSI_SATA_PROMISE is not set
 # CONFIG_SCSI_SATA_VIA is not set
+# CONFIG_SCSI_SATA_VITESSE is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -278,7 +286,6 @@
 # CONFIG_MD_RAID6 is not set
 # CONFIG_MD_MULTIPATH is not set
 CONFIG_BLK_DEV_DM=y
-CONFIG_DM_IOCTL_V4=y
 # CONFIG_DM_CRYPT is not set
 
 #
@@ -296,6 +303,8 @@
 #
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
 CONFIG_IEEE1394_OUI_DB=y
+CONFIG_IEEE1394_EXTRA_CONFIG_ROMS=y
+CONFIG_IEEE1394_CONFIG_ROM_IP1394=y
 
 #
 # Device Drivers
@@ -350,15 +359,72 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
 # CONFIG_ARPD is not set
-CONFIG_INET_ECN=y
+# CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=m
 CONFIG_INET_ESP=m
 CONFIG_INET_IPCOMP=m
+
+#
+# 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 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_FTP is not set
+# CONFIG_IP_NF_IRC is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+CONFIG_IP_NF_QUEUE=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_LIMIT=y
+CONFIG_IP_NF_MATCH_IPRANGE=y
+CONFIG_IP_NF_MATCH_MAC=y
+CONFIG_IP_NF_MATCH_PKTTYPE=y
+CONFIG_IP_NF_MATCH_MARK=y
+CONFIG_IP_NF_MATCH_MULTIPORT=y
+CONFIG_IP_NF_MATCH_TOS=y
+CONFIG_IP_NF_MATCH_RECENT=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_DSCP=y
+CONFIG_IP_NF_MATCH_AH_ESP=y
+CONFIG_IP_NF_MATCH_LENGTH=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_MATCH_TCPMSS=y
+CONFIG_IP_NF_MATCH_HELPER=y
+CONFIG_IP_NF_MATCH_STATE=y
+CONFIG_IP_NF_MATCH_CONNTRACK=y
+CONFIG_IP_NF_MATCH_OWNER=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_SAME=y
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_TARGET_TOS=y
+CONFIG_IP_NF_TARGET_ECN=y
+CONFIG_IP_NF_TARGET_DSCP=y
+CONFIG_IP_NF_TARGET_MARK=y
+CONFIG_IP_NF_TARGET_CLASSIFY=y
+CONFIG_IP_NF_TARGET_LOG=y
+CONFIG_IP_NF_TARGET_ULOG=y
+CONFIG_IP_NF_TARGET_TCPMSS=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 
@@ -468,6 +534,7 @@
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # Wan interfaces
@@ -488,6 +555,8 @@
 # Bluetooth support
 #
 # CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # ISDN subsystem
@@ -533,11 +602,13 @@
 CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_ATKBD is not set
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 CONFIG_INPUT_MOUSE=y
 # CONFIG_MOUSE_PS2 is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
@@ -563,11 +634,6 @@
 CONFIG_LEGACY_PTYS=y
 CONFIG_LEGACY_PTY_COUNT=256
 CONFIG_HVC_CONSOLE=y
-
-#
-# Mice
-#
-# CONFIG_BUSMOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -579,7 +645,6 @@
 # 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
@@ -613,7 +678,6 @@
 # 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
@@ -626,34 +690,45 @@
 # 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
+# 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_DS1621 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_LM80 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_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
 # CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -667,6 +742,7 @@
 # Graphics support
 #
 CONFIG_FB=y
+# CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
 CONFIG_FB_OF=y
 # CONFIG_FB_CONTROL is not set
@@ -734,6 +810,7 @@
 # USB Host Controller Drivers
 #
 CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_UHCI_HCD is not set
 
@@ -742,9 +819,9 @@
 #
 # CONFIG_USB_BLUETOOTH_TTY is not set
 CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-CONFIG_USB_STORAGE=m
-CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_PRINTER=y
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
 CONFIG_USB_STORAGE_DATAFAB=y
 CONFIG_USB_STORAGE_FREECOM=y
 CONFIG_USB_STORAGE_ISD200=y
@@ -768,7 +845,9 @@
 # CONFIG_USB_WACOM is not set
 # CONFIG_USB_KBTAB is not set
 # CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
 # CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
 
 #
 # USB Imaging devices
@@ -798,6 +877,7 @@
 #
 # USB Host-to-Host Cables
 #
+CONFIG_USB_ALI_M5632=y
 CONFIG_USB_AN2720=y
 CONFIG_USB_BELKIN=y
 CONFIG_USB_GENESYS=y
@@ -869,7 +949,6 @@
 # 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
@@ -964,12 +1043,13 @@
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
-CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_SMB_FS is not set
 CONFIG_CIFS=m
 # CONFIG_NCP_FS is not set
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 # CONFIG_AFS_FS is not set
 
 #
@@ -981,7 +1061,11 @@
 # CONFIG_AMIGA_PARTITION is not set
 # CONFIG_ATARI_PARTITION is not set
 CONFIG_MAC_PARTITION=y
-# CONFIG_MSDOS_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
@@ -1062,18 +1146,20 @@
 CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=m
 CONFIG_CRYPTO_SHA256=m
 CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
 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_MICHAEL_MIC is not set
 CONFIG_CRYPTO_TEST=m
 
 #
diff -Nru a/arch/ppc64/configs/iSeries_defconfig b/arch/ppc64/configs/iSeries_defconfig
--- a/arch/ppc64/configs/iSeries_defconfig	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc64/configs/iSeries_defconfig	Sat Apr  3 19:38:56 2004
@@ -47,6 +47,7 @@
 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=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 @@
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -115,10 +118,10 @@
 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_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_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_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # Wan interfaces
@@ -457,6 +466,10 @@
 # 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 @@
 # 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_I2C is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -742,7 +758,6 @@
 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_AES=m
 CONFIG_CRYPTO_CAST5=m
 CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_TEST=m
 
diff -Nru a/arch/ppc64/configs/pSeries_defconfig b/arch/ppc64/configs/pSeries_defconfig
--- a/arch/ppc64/configs/pSeries_defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/configs/pSeries_defconfig	Sat Apr  3 19:38:55 2004
@@ -47,6 +47,7 @@
 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_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 @@
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -132,10 +135,10 @@
 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_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
@@ -194,7 +197,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -222,6 +224,12 @@
 # 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 +281,6 @@
 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 +522,7 @@
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # Wan interfaces
@@ -535,6 +543,10 @@
 # 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 +645,6 @@
 # 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
@@ -667,7 +678,6 @@
 # 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
@@ -679,7 +689,6 @@
 # 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
@@ -707,6 +716,10 @@
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -720,6 +733,7 @@
 # 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 +790,7 @@
 #
 # USB support
 #
-CONFIG_USB=m
+CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
 #
@@ -789,8 +803,8 @@
 #
 # 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 +813,7 @@
 # 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 +827,10 @@
 #
 # 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 +1084,7 @@
 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 -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig
--- a/arch/ppc64/defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc64/defconfig	Sat Apr  3 19:38:42 2004
@@ -47,6 +47,7 @@
 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_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 @@
 # Generic Driver Options
 #
 CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -132,10 +135,10 @@
 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_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
@@ -194,7 +197,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -222,6 +224,12 @@
 # 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 +281,6 @@
 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 +522,7 @@
 # CONFIG_TMS380TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # Wan interfaces
@@ -535,6 +543,10 @@
 # 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 +645,6 @@
 # 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
@@ -667,7 +678,6 @@
 # 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
@@ -679,7 +689,6 @@
 # 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
@@ -707,6 +716,10 @@
 # CONFIG_I2C_DEBUG_CHIP is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -720,6 +733,7 @@
 # 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 +790,7 @@
 #
 # USB support
 #
-CONFIG_USB=m
+CONFIG_USB=y
 # CONFIG_USB_DEBUG is not set
 
 #
@@ -789,8 +803,8 @@
 #
 # 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 +813,7 @@
 # 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 +827,10 @@
 #
 # 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 +1084,7 @@
 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 -Nru a/arch/ppc64/kernel/HvCall.c b/arch/ppc64/kernel/HvCall.c
--- a/arch/ppc64/kernel/HvCall.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/kernel/HvCall.c	Sat Apr  3 19:38:55 2004
@@ -19,7 +19,7 @@
 {
 	struct HvLpBufferList hv_buf;
 	u64 left_this_page;
-	u64 cur = virt_to_absolute((unsigned long)buffer);
+	u64 cur = virt_to_abs(buffer);
 
 	while (len) {
 		hv_buf.addr = cur;
@@ -29,7 +29,7 @@
 		hv_buf.len = left_this_page;
 		len -= left_this_page;
 		HvCall2(HvCallBaseWriteLogBuffer,
-				virt_to_absolute((unsigned long)&hv_buf),
+				virt_to_abs(&hv_buf),
 				left_this_page);
 		cur = (cur & PAGE_MASK) + PAGE_SIZE;
 	}
diff -Nru a/arch/ppc64/kernel/HvLpConfig.c b/arch/ppc64/kernel/HvLpConfig.c
--- a/arch/ppc64/kernel/HvLpConfig.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/kernel/HvLpConfig.c	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
--- a/arch/ppc64/kernel/Makefile	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc64/kernel/Makefile	Sat Apr  3 19:38:56 2004
@@ -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 @@
 			     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 -Nru a/arch/ppc64/kernel/bitops.c b/arch/ppc64/kernel/bitops.c
--- a/arch/ppc64/kernel/bitops.c	Sat Apr  3 19:38:45 2004
+++ b/arch/ppc64/kernel/bitops.c	Sat Apr  3 19:38:45 2004
@@ -3,6 +3,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <asm/bitops.h>
 #include <asm/byteorder.h>
 
@@ -19,7 +20,7 @@
 	offset &= 63UL;
 	if (offset) {
 		tmp = *(p++);
-		tmp |= ~0UL >> (64-offset);
+		tmp |= ~0UL >> (64 - offset);
 		if (size < 64)
 			goto found_first;
 		if (~tmp)
@@ -40,12 +41,15 @@
 found_first:
 	tmp |= ~0UL << size;
 	if (tmp == ~0UL)	/* Are any bits zero? */
-		return result + size; /* Nope. */
+		return result + size;	/* Nope. */
 found_middle:
 	return result + ffz(tmp);
 }
 
-unsigned long find_next_bit(unsigned long *addr, unsigned long size, unsigned long offset)
+EXPORT_SYMBOL(find_next_zero_bit);
+
+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;
@@ -77,62 +81,67 @@
 
 found_first:
 	tmp &= (~0UL >> (64 - size));
-	if (tmp == 0UL)        /* Are any bits set? */
-		return result + size; /* Nope. */
+	if (tmp == 0UL)		/* Are any bits set? */
+		return result + size;	/* Nope. */
 found_middle:
 	return result + __ffs(tmp);
 }
 
-static __inline__ unsigned int ext2_ilog2(unsigned int x) 
+EXPORT_SYMBOL(find_next_bit);
+
+static inline unsigned int ext2_ilog2(unsigned int x)
 {
 	int lz;
 
-	asm("cntlzw %0,%1" : "=r" (lz) : "r" (x));
+	asm("cntlzw %0,%1": "=r"(lz):"r"(x));
 	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;
-        unsigned int tmp;
-
-        if (offset >= size)
-                return size;
-        size -= result;
-        offset &= 31;
-        if (offset) {
-                tmp = cpu_to_le32p(p++);
-                tmp |= ~0U >> (32-offset); /* bug or feature ? */
-                if (size < 32)
-                        goto found_first;
-                if (tmp != ~0)
-                        goto found_middle;
-                size -= 32;
-                result += 32;
-        }
-        while (size >= 32) {
-                if ((tmp = cpu_to_le32p(p++)) != ~0)
-                        goto found_middle;
-                result += 32;
-                size -= 32;
-        }
-        if (!size)
-                return result;
-        tmp = cpu_to_le32p(p);
+	unsigned int *p = ((unsigned int *)addr) + (offset >> 5);
+	unsigned int result = offset & ~31;
+	unsigned int tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= 31;
+	if (offset) {
+		tmp = cpu_to_le32p(p++);
+		tmp |= ~0U >> (32 - offset);	/* bug or feature ? */
+		if (size < 32)
+			goto found_first;
+		if (tmp != ~0)
+			goto found_middle;
+		size -= 32;
+		result += 32;
+	}
+	while (size >= 32) {
+		if ((tmp = cpu_to_le32p(p++)) != ~0)
+			goto found_middle;
+		result += 32;
+		size -= 32;
+	}
+	if (!size)
+		return result;
+	tmp = cpu_to_le32p(p);
 found_first:
-        tmp |= ~0 << size;
-        if (tmp == ~0)          /* Are any bits zero? */
-                return result + size; /* Nope. */
+	tmp |= ~0 << size;
+	if (tmp == ~0)		/* Are any bits zero? */
+		return result + size;	/* Nope. */
 found_middle:
-        return result + ext2_ffz(tmp);
+	return result + ext2_ffz(tmp);
 }
+
+EXPORT_SYMBOL(find_next_zero_le_bit);
diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c
--- a/arch/ppc64/kernel/chrp_setup.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/kernel/chrp_setup.c	Sat Apr  3 19:38:41 2004
@@ -88,14 +88,11 @@
 extern unsigned long ppc_proc_freq;
 extern unsigned long ppc_tb_freq;
 
-void 
-chrp_get_cpuinfo(struct seq_file *m)
+void chrp_get_cpuinfo(struct seq_file *m)
 {
 	struct device_node *root;
 	const char *model = "";
 
-	seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq);
-
 	root = of_find_node_by_path("/");
 	if (root)
 		model = get_property(root, "model", NULL);
@@ -209,15 +206,17 @@
 		fwnmi_active = 1;
 }
 
-
 /* Early initialization.  Relocation is on but do not reference unbolted pages */
 void __init pSeries_init_early(void)
 {
-#ifdef CONFIG_PPC_PSERIES	/* This ifdef should go away */
 	void *comport;
 
 	hpte_init_pSeries();
-	tce_init_pSeries();
+
+	if (ppc64_iommu_off)
+		pci_dma_init_direct();
+	else
+		tce_init_pSeries();
 
 #ifdef CONFIG_SMP
 	smp_init_pSeries();
@@ -230,7 +229,6 @@
 	ppc_md.udbg_putc = udbg_putc;
 	ppc_md.udbg_getc = udbg_getc;
 	ppc_md.udbg_getc_poll = udbg_getc_poll;
-#endif
 }
 
 void __init
@@ -253,7 +251,6 @@
 #endif
 
 	ppc_md.setup_arch     = chrp_setup_arch;
-	ppc_md.setup_residual = NULL;
 	ppc_md.get_cpuinfo    = chrp_get_cpuinfo;
 	if(naca->interrupt_controller == IC_OPEN_PIC) {
 		ppc_md.init_IRQ       = pSeries_init_openpic; 
@@ -418,46 +415,64 @@
 
 extern void setup_default_decr(void);
 
+/* Some sane defaults: 125 MHz timebase, 1GHz processor */
+#define DEFAULT_TB_FREQ		125000000UL
+#define DEFAULT_PROC_FREQ	(DEFAULT_TB_FREQ * 8)
+
 void __init pSeries_calibrate_decr(void)
 {
 	struct device_node *cpu;
 	struct div_result divres;
-	int *fp;
-	unsigned long freq, processor_freq;
+	unsigned int *fp;
+	int node_found;
 
 	/*
 	 * The cpu node should have a timebase-frequency property
 	 * to tell us the rate at which the decrementer counts.
 	 */
-	freq = 16666000;        /* hardcoded default */
 	cpu = of_find_node_by_type(NULL, "cpu");
+
+	ppc_tb_freq = DEFAULT_TB_FREQ;		/* hardcoded default */
+	node_found = 0;
 	if (cpu != 0) {
-		fp = (int *) get_property(cpu, "timebase-frequency", NULL);
-		if (fp != 0)
-			freq = *fp;
+		fp = (unsigned int *)get_property(cpu, "timebase-frequency",
+						  NULL);
+		if (fp != 0) {
+			node_found = 1;
+			ppc_tb_freq = *fp;
+		}
 	}
-	ppc_tb_freq = freq;
-	processor_freq = freq;
+	if (!node_found)
+		printk(KERN_ERR "WARNING: Estimating decrementer frequency "
+				"(not found)\n");
+
+	ppc_proc_freq = DEFAULT_PROC_FREQ;
+	node_found = 0;
 	if (cpu != 0) {
-		fp = (int *) get_property(cpu, "clock-frequency", NULL);
-		if (fp != 0)
-			processor_freq = *fp;
+		fp = (unsigned int *)get_property(cpu, "clock-frequency",
+						  NULL);
+		if (fp != 0) {
+			node_found = 1;
+			ppc_proc_freq = *fp;
+		}
 	}
-	ppc_proc_freq = processor_freq;
+	if (!node_found)
+		printk(KERN_ERR "WARNING: Estimating processor frequency "
+				"(not found)\n");
+
 	of_node_put(cpu);
 
-	printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
-	       freq/1000000, freq%1000000);
-	printk("time_init: processor frequency   = %lu.%.6lu MHz\n",
-	       processor_freq/1000000, processor_freq%1000000);
+	printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n",
+	       ppc_tb_freq/1000000, ppc_tb_freq%1000000);
+	printk(KERN_INFO "time_init: processor frequency   = %lu.%.6lu MHz\n",
+	       ppc_proc_freq/1000000, ppc_proc_freq%1000000);
 
-	tb_ticks_per_jiffy = freq / HZ;
+	tb_ticks_per_jiffy = ppc_tb_freq / HZ;
 	tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
-	tb_ticks_per_usec = freq / 1000000;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
+	tb_ticks_per_usec = ppc_tb_freq / 1000000;
+	tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
+	div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres);
 	tb_to_xs = divres.result_low;
 
 	setup_default_decr();
 }
-
diff -Nru a/arch/ppc64/kernel/dma.c b/arch/ppc64/kernel/dma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/dma.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/arch/ppc64/kernel/eeh.c b/arch/ppc64/kernel/eeh.c
--- a/arch/ppc64/kernel/eeh.c	Sat Apr  3 19:38:45 2004
+++ b/arch/ppc64/kernel/eeh.c	Sat Apr  3 19:38:45 2004
@@ -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 @@
 	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 @@
 	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 @@
 	     *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 @@
 	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 @@
 		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 @@
 				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 @@
  * 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 @@
 			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 @@
 	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 @@
 	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 @@
 	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 @@
  * 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 @@
  * 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 @@
 		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 @@
 			eeh_opts[eeh_opts_last++] = '\0';
 		}
 	}
+
 	return 1;
 }
 
@@ -476,6 +874,5 @@
 	return eeh_parm(str, 1);
 }
 
-__initcall(eeh_init_proc);
 __setup("eeh-off", eehoff_parm);
 __setup("eeh-on", eehon_parm);
diff -Nru a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S
--- a/arch/ppc64/kernel/entry.S	Sat Apr  3 19:38:40 2004
+++ b/arch/ppc64/kernel/entry.S	Sat Apr  3 19:38:40 2004
@@ -139,7 +139,7 @@
 91:
 #endif
 	li	r10,-_LAST_ERRNO
-	cmpl	0,r3,r10
+	cmpld	0,r3,r10
 	blt	30f
 	neg	r3,r3
 22:	ld	r10,_CCR(r1)	/* Set SO bit in CR */
@@ -194,7 +194,7 @@
 _GLOBAL(ret_from_syscall_2)
 	std	r3,RESULT(r1)	/* Save result */	
 	li	r10,-_LAST_ERRNO
-	cmpl	0,r3,r10
+	cmpld	0,r3,r10
 	blt	60f
 	neg	r3,r3
 57:	ld	r10,_CCR(r1)	/* Set SO bit in CR */
@@ -289,10 +289,35 @@
 	std	r23,_CCR(r1)
 	std	r1,KSP(r3)	/* Set old stack pointer */
 
+#ifdef CONFIG_SMP
+	/* We need a sync somewhere here to make sure that if the
+	 * previous task gets rescheduled on another CPU, it sees all
+	 * stores it has performed on this one.
+	 */
+	sync
+#endif /* CONFIG_SMP */
+
 	addi	r6,r4,-THREAD	/* Convert THREAD to 'current' */
 	std	r6,PACACURRENT(r13)	/* Set new 'current' */
 
-	ld	r1,KSP(r4)	/* Load new stack pointer */
+	ld	r8,KSP(r4)	/* new stack pointer */
+BEGIN_FTR_SECTION
+	clrrdi	r6,r8,28	/* get its ESID */
+	clrrdi	r9,r1,28	/* get current sp ESID */
+	clrldi.	r0,r6,2		/* is new ESID c00000000? */
+	cmpd	cr1,r6,r9	/* or is new ESID the same as current ESID? */
+	cror	eq,4*cr1+eq,eq
+	beq	2f		/* if yes, don't slbie it */
+	oris	r6,r6,0x0800	/* set C (class) bit */
+	slbie	r6
+2:
+END_FTR_SECTION_IFSET(CPU_FTR_SLB)
+	clrrdi	r7,r8,THREAD_SHIFT	/* base of new stack */
+	addi	r7,r7,THREAD_SIZE-INT_FRAME_SIZE
+
+	mr	r1,r8		/* start using new stack pointer */
+	std	r7,PACAKSAVE(r13)
+
 	ld	r6,_CCR(r1)
 	mtcrf	0xFF,r6
 
@@ -357,7 +382,6 @@
 	addi	r0,r1,INT_FRAME_SIZE	/* size of frame */
 	ld	r4,PACACURRENT(r13)
 	std	r0,THREAD+KSP(r4)	/* save kernel stack pointer */
-	std	r1,PACAKSAVE(r13)	/* save exception stack pointer */
 
 	/*
 	 * r13 is our per cpu area, only restore it if we are returning to
@@ -388,6 +412,10 @@
 4:	stb	r5,PACAPROCENABLED(r4)
 #endif
 
+	ld	r3,_MSR(r1)
+	andi.	r3,r3,MSR_RI
+	beq-	unrecov_restore
+
 	ld	r3,_CTR(r1)
 	ld	r0,_LINK(r1)
 	mtctr	r3
@@ -438,6 +466,11 @@
 	addi	r4,r1,STACK_FRAME_OVERHEAD
 	bl	.do_signal
 	b	.ret_from_except
+
+unrecov_restore:
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.unrecoverable_exception
+	b	unrecov_restore
 
 #ifdef CONFIG_PPC_PSERIES
 /*
diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
--- a/arch/ppc64/kernel/head.S	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/kernel/head.S	Sat Apr  3 19:38:43 2004
@@ -275,14 +275,15 @@
 	mfspr	r22,SPRG1;		/* Save r21 in exc. frame      */ \
 	std	r22,EX_R21(r21);	                                  \
 	std     r21,PACAEXCSP(r20);     /* update exception stack ptr  */ \
-		                        /*   iff no protection flt     */ \
 	ld	r22,EX_SRR1(r21);	/* Get SRR1 from exc. frame    */ \
 	andi.   r22,r22,MSR_PR;         /* Set CR for later branch     */ \
 	mr      r22,r1;                 /* Save r1                     */ \
 	subi    r1,r1,INT_FRAME_SIZE;   /* alloc frame on kernel stack */ \
 	beq-    1f;                                                       \
 	ld      r1,PACAKSAVE(r20);      /* kernel stack to use         */ \
-1:      std     r22,GPR1(r1);           /* save r1 in stackframe       */ \
+1:      cmpdi	cr1,r1,0;		/* check if r1 is in userspace */ \
+	bge	cr1,bad_stack;		/* abort if it is	       */ \
+	std     r22,GPR1(r1);           /* save r1 in stackframe       */ \
 	std     r22,0(r1);              /* make stack chain pointer    */ \
 	std     r23,_CCR(r1);           /* save CR in stackframe       */ \
 	ld	r22,EX_R20(r21);	/* move r20 to stackframe      */ \
@@ -495,6 +496,9 @@
 	.globl SystemReset_Iseries
 SystemReset_Iseries:
 	mfspr	r13,SPRG3		/* Get paca address */
+	mfmsr	r24
+	ori	r24,r24,MSR_RI
+	mtmsrd	r24			/* RI on */
 	lhz	r24,PACAPACAINDEX(r13)	/* Get processor # */
 	cmpi	0,r24,0			/* Are we processor 0? */
 	beq	.__start_initialization_iSeries	/* Start up the first processor */
@@ -610,12 +614,68 @@
 #else
 	STD_EXCEPTION_COMMON(0x1700, AltivecAssist, .UnknownException )
 #endif
+
+/*
+ * Here the exception frame is filled out and we have detected that
+ * the kernel stack pointer is bad.  R23 contains the saved CR, r20
+ * points to the paca, r21 points to the exception frame, and r22
+ * contains the (bad) kernel stack pointer.
+ * We switch to using the paca guard page as an emergency stack,
+ * save the registers on there, and call kernel_bad_stack(),
+ * which panics.
+ */
+bad_stack:
+	addi	r1,r20,8192-64-INT_FRAME_SIZE
+	std	r22,GPR1(r1)
+	std	r23,_CCR(r1)
+	ld	r22,EX_R20(r21)
+	std	r22,GPR20(r1)
+	ld	r23,EX_R21(r21)
+	std	r23,GPR21(r1)
+	ld	r22,EX_R22(r21)
+	std	r22,GPR22(r1)
+	ld	r23,EX_R23(r21)
+	std	r23,GPR23(r1)
+	ld	r23,EX_DAR(r21)
+	std	r23,_DAR(r1)
+	lwz     r22,EX_DSISR(r21)
+	std	r22,_DSISR(r1)
+	lwz	r23,EX_TRAP(r21)
+	std	r23,TRAP(r1)
+	ld	r22,EX_SRR0(r21)
+	ld	r23,EX_SRR1(r21)
+	std	r22,_NIP(r1)
+	std	r23,_MSR(r1)
+	addi	r21,r21,-EXC_FRAME_SIZE
+	std	r21,PACAEXCSP(r20)
+	mflr	r22
+	std	r22,_LINK(r1)
+	mfctr	r23
+	std	r23,_CTR(r1)
+	mfspr	r22,XER
+	std	r22,_XER(r1)
+	SAVE_GPR(0, r1)
+	SAVE_10GPRS(2, r1)
+	SAVE_8GPRS(12, r1)
+	SAVE_8GPRS(24, r1)
+	addi	r21,r1,INT_FRAME_SIZE
+	std	r21,0(r1)
+	li	r22,0
+	std	r22,0(r21)
+	ld	r2,PACATOC(r20)
+	mr	r13,r20
+1:	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.kernel_bad_stack
+	b	1b
+
 /*
  * Return from an exception which is handled without calling
  * save_remaining_regs.  The caller is assumed to have done
  * EXCEPTION_PROLOG_COMMON.
  */
 fast_exception_return:
+	andi.	r3,r23,MSR_RI		/* check if RI is set */
+	beq-	unrecov_fer
 	ld      r3,_CCR(r1)
 	ld      r4,_LINK(r1)
 	ld      r5,_CTR(r1)
@@ -639,6 +699,14 @@
 	ld      r1,GPR1(r1)
 	rfid
 
+unrecov_fer:
+	li	r6,0x4000
+	li	r20,0
+	bl	.save_remaining_regs
+1:	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.unrecoverable_exception
+	b	1b
+
 /*
  * Here r20 points to the PACA, r21 to the exception frame,
  * r23 contains the saved CR.
@@ -996,6 +1064,11 @@
 	ld      r21,PACAEXCSP(r20)      /* Get the exception frame pointer */
 	addi    r21,r21,EXC_FRAME_SIZE
 	lwz	r23,EX_CCR(r21)		/* get saved CR */
+
+	ld	r22,EX_SRR1(r21)
+	andi.	r22,r22,MSR_RI
+	beq-	unrecov_stab
+
 	/* note that this is almost identical to maskable_exception_exit */
 	mtcr    r23                     /* restore CR */
 
@@ -1014,6 +1087,15 @@
 	mfspr	r21,SPRG1
 	rfid
 
+unrecov_stab:
+	EXCEPTION_PROLOG_COMMON
+	li	r6,0x4100
+	li	r20,0
+	bl	.save_remaining_regs
+1:	addi	r3,r1,STACK_FRAME_OVERHEAD
+	bl	.unrecoverable_exception
+	b	1b
+
 /*
  * r20 points to the PACA, r21 to the exception frame,
  * r23 contains the saved CR.
@@ -1052,15 +1134,23 @@
 	slbmfee	r21,r22
 	srdi	r21,r21,27
 	/*
-	 * This is incorrect (r1 is not the kernel stack) if we entered
-	 * from userspace but there is no critical window from userspace
-	 * so this should be OK. Also if we cast out the userspace stack
-	 * segment while in userspace we will fault it straight back in.
+	 * Use paca->ksave as the value of the kernel stack pointer,
+	 * because this is valid at all times.
+	 * The >> 27 (rather than >> 28) is so that the LSB is the
+	 * valid bit - this way we check valid and ESID in one compare.
+	 * In order to completely close the tiny race in the context
+	 * switch (between updating r1 and updating paca->ksave),
+	 * we check against both r1 and paca->ksave.
 	 */
 	srdi	r23,r1,27
 	ori	r23,r23,1
 	cmpd	r23,r21
 	beq-	1b
+	ld	r23,PACAKSAVE(r20)
+	srdi	r23,r23,27
+ 	ori	r23,r23,1
+ 	cmpd	r23,r21
+ 	beq-	1b
 
 	/* r20 = paca, r22 = entry */
 
@@ -1117,6 +1207,10 @@
 	lwz	r23,EX_CCR(r21)		/* get saved CR */
 	/* note that this is almost identical to maskable_exception_exit */
 
+	ld	r22,EX_SRR1(r21)
+	andi.	r22,r22,MSR_RI
+	beq-	unrecov_stab
+
 	/*
 	 * Until everyone updates binutils hardwire the POWER4 optimised
 	 * single field mtcrf
@@ -1190,9 +1284,8 @@
 
 	/*
 	 * Indicate that r1 contains the kernel stack and
-	 * get the Kernel TOC and CURRENT pointers from the paca
+	 * get the Kernel TOC pointer from the paca
 	 */
-	std	r22,PACAKSAVE(r13)	/* r1 is now kernel sp */
 	ld	r2,PACATOC(r13)		/* Get Kernel TOC pointer */
 
 	/*
@@ -1764,7 +1857,6 @@
 
 	std	r2,PACATOC(r13)
 	li	r6,0
-	std	r6,PACAKSAVE(r13)
 	stb	r6,PACAPROCENABLED(r13)
 
 #ifndef CONFIG_PPC_ISERIES
@@ -1783,6 +1875,7 @@
 	ldx	r1,r3,r28
 	addi	r1,r1,THREAD_SIZE
 	subi	r1,r1,STACK_FRAME_OVERHEAD
+	std	r1,PACAKSAVE(r13)
 
 	ld	r3,PACASTABREAL(r13)    /* get raddr of segment table       */
 	ori	r4,r3,1			/* turn on valid bit                */
@@ -2055,7 +2148,7 @@
 
 	std	r2,PACATOC(r13)
 	li	r5,0
-	std	r0,PACAKSAVE(r13)
+	std	r1,PACAKSAVE(r13)
 
 	/* Restore the parms passed in from the bootloader. */
 	mr	r3,r31
diff -Nru a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c
--- a/arch/ppc64/kernel/iSeries_VpdInfo.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/kernel/iSeries_VpdInfo.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 	strcpy(&LocationPtr->CardLocation[0], &DevNode->CardLocation[0]);
 	return LocationPtr;
 }
+EXPORT_SYMBOL(iSeries_GetLocationData);
 
 /*
  * Formats the device information.
@@ -291,7 +293,8 @@
 		return;
 	}
 	BusVpdLen = HvCallPci_getBusVpd(ISERIES_BUS(DevNode),
-			REALADDR(BusVpdPtr), BUS_VPDSIZE);
+					ISERIES_HV_ADDR(BusVpdPtr),
+					BUS_VPDSIZE);
 	if (BusVpdLen == 0) {
 		kfree(BusVpdPtr);
 		printk("PCI: Bus VPD Buffer zero length.\n");
diff -Nru a/arch/ppc64/kernel/iSeries_iommu.c b/arch/ppc64/kernel/iSeries_iommu.c
--- a/arch/ppc64/kernel/iSeries_iommu.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/kernel/iSeries_iommu.c	Sat Apr  3 19:38:41 2004
@@ -76,7 +76,7 @@
 	
 	while (npages--) {
 		tce.te_word = 0;
-		tce.te_bits.tb_rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+		tce.te_bits.tb_rpn = virt_to_abs(uaddr) >> PAGE_SHIFT;
 
 		if (tbl->it_type == TCE_VB) {
 			/* Virtual Bus */
@@ -130,7 +130,7 @@
 	cb.itc_busno = 255;    /* Bus 255 is the virtual bus */
 	cb.itc_virtbus = 0xff; /* Ask for virtual bus */
 	
-	cbp = virt_to_absolute((unsigned long)&cb);
+	cbp = virt_to_abs(&cb);
 	HvCallXm_getTceTableParms(cbp);
 	
 	veth_iommu_table.it_size        = cb.itc_size / 2;
@@ -209,7 +209,7 @@
 	parms->itc_slotno  = dn->LogicalSlot;
 	parms->itc_virtbus = 0;
 
-	HvCallXm_getTceTableParms(REALADDR(parms));
+	HvCallXm_getTceTableParms(ISERIES_HV_ADDR(parms));
 
 	if (parms->itc_size == 0)
 		panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms);
diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c
--- a/arch/ppc64/kernel/iSeries_pci.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc64/kernel/iSeries_pci.c	Sat Apr  3 19:38:56 2004
@@ -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>
 
@@ -102,47 +103,6 @@
 	       Error_Text, Bus, SubBus, AgentId, HvRc);
 }
 
-#if 0
-/*
- * Dump the iSeries Temp Device Node 
- * <4>buswalk [swapper : - DeviceNode: 0xC000000000634300
- * <4>00. Device Node   = 0xC000000000634300
- * <4>    - PciDev      = 0x0000000000000000
- * <4>    - tDevice     = 0x  17:01.00  0x1022 00
- * <4>  4. Device Node = 0xC000000000634480
- * <4>     - PciDev    = 0x0000000000000000
- * <4>     - Device    = 0x  18:38.16 Irq:0xA7 Vendor:0x1014  Flags:0x00
- * <4>     - Devfn     = 0xB0: 22.18
- */
-void dumpDevice_Node(struct iSeries_Device_Node *DevNode)
-{
-	udbg_printf("Device Node      = 0x%p\n", DevNode);
-	udbg_printf("     - PciDev    = 0x%p\n", DevNode->PciDev);
-	udbg_printf("     - Device    = 0x%4X:%02X.%02X (0x%02X)\n",
-			ISERIES_BUS(DevNode), ISERIES_SUBBUS(DevNode),
-			DevNode->AgentId, DevNode->DevFn);
-	udbg_printf("     - LSlot     = 0x%02X\n", DevNode->LogicalSlot);
-	udbg_printf("     - TceTable  = 0x%p\n  ", DevNode->DevTceTable);
-	udbg_printf("     - DSA       = 0x%04X\n", ISERIES_DSA(DevNode) >> 32);
-	udbg_printf("                 = Irq:0x%02X Vendor:0x%04X  Flags:0x%02X\n",
-			DevNode->Irq, DevNode->Vendor, DevNode->Flags);
-	udbg_printf("     - Location  = %s\n", DevNode->CardLocation);
-}
-
-/*
- * Walk down the device node chain 
- */
-static void list_device_nodes(void)
-{
-	struct list_head *Device_Node_Ptr = iSeries_Global_Device_List.next;
-
-	while (Device_Node_Ptr != &iSeries_Global_Device_List) {
-		dumpDevice_Node((struct iSeries_Device_Node*)Device_Node_Ptr);
-		Device_Node_Ptr = Device_Node_Ptr->next;
-	}
-}
-#endif
-
 /*
  * build_device_node(u16 Bus, int SubBus, u8 DevFn)
  */
@@ -317,7 +277,7 @@
 	 */
 	for (IdSel = 1; IdSel < MaxAgents; ++IdSel) {
     		HvRc = HvCallPci_getDeviceInfo(bus, SubBus, IdSel,
-				REALADDR(DevInfo),
+				ISERIES_HV_ADDR(DevInfo),
 				sizeof(struct HvCallPci_DeviceInfo));
 		if (HvRc == 0) {
 			if (DevInfo->deviceType == HvCallPci_NodeDevice)
@@ -358,7 +318,7 @@
 					"PCI:Connect EADs: 0x%02X.%02X.%02X\n",
 					bus, SubBus, AgentId);
 	    		HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId,
-					REALADDR(BridgeInfo),
+					ISERIES_HV_ADDR(BridgeInfo),
 					sizeof(struct HvCallPci_BridgeInfo));
 	 		if (HvRc == 0) {
 				printk("bridge info: type %x subbus %x maxAgents %x maxsubbus %x logslot %x\n",
@@ -472,6 +432,7 @@
 	}
 	return dest;
 }
+EXPORT_SYMBOL(iSeries_memset_io);
 
 void *iSeries_memcpy_toio(void *dest, void *source, size_t count)
 {
@@ -485,6 +446,7 @@
 	}
 	return dest;
 }
+EXPORT_SYMBOL(iSeries_memcpy_toio);
 
 void *iSeries_memcpy_fromio(void *dest, void *source, size_t count)
 {
@@ -498,6 +460,7 @@
 	}
 	return dest;
 }
+EXPORT_SYMBOL(iSeries_memcpy_fromio);
 
 /*
  * Look down the chain to find the matching Device Device
@@ -708,6 +671,7 @@
 
 	return (u8)ret.value;
 }
+EXPORT_SYMBOL(iSeries_Read_Byte);
 
 u16 iSeries_Read_Word(void *IoAddress)
 {
@@ -737,6 +701,7 @@
 
 	return swab16((u16)ret.value);
 }
+EXPORT_SYMBOL(iSeries_Read_Word);
 
 u32 iSeries_Read_Long(void *IoAddress)
 {
@@ -766,6 +731,7 @@
 
 	return swab32((u32)ret.value);
 }
+EXPORT_SYMBOL(iSeries_Read_Long);
 
 /*
  * Write MM I/O Instructions for the iSeries
@@ -799,6 +765,7 @@
 		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 +792,7 @@
 		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 +819,7 @@
 		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 -Nru a/arch/ppc64/kernel/iSeries_pci_reset.c b/arch/ppc64/kernel/iSeries_pci_reset.c
--- a/arch/ppc64/kernel/iSeries_pci_reset.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc64/kernel/iSeries_pci_reset.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 	}
 	return DeviceNode->ReturnCode;
 }
+EXPORT_SYMBOL(iSeries_Device_ToggleReset);
diff -Nru a/arch/ppc64/kernel/iSeries_proc.c b/arch/ppc64/kernel/iSeries_proc.c
--- a/arch/ppc64/kernel/iSeries_proc.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc64/kernel/iSeries_proc.c	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
--- a/arch/ppc64/kernel/iSeries_setup.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc64/kernel/iSeries_setup.c	Sat Apr  3 19:38:54 2004
@@ -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 */
@@ -312,7 +311,6 @@
 	iSeries_recal_titan = HvCallXm_loadTod();
 
 	ppc_md.setup_arch = iSeries_setup_arch;
-	ppc_md.setup_residual = iSeries_setup_residual;
 	ppc_md.get_cpuinfo = iSeries_get_cpuinfo;
 	ppc_md.init_IRQ = iSeries_init_IRQ;
 	ppc_md.get_irq = iSeries_get_irq;
@@ -393,12 +391,9 @@
 
 	iSeries_setup_dprofile();
 
-	iSeries_proc_early_init();
 	mf_init();
 	mf_initialized = 1;
 	mb();
-
-	iSeries_proc_callback(&pmc_proc_init);
 }
 
 /*
@@ -663,8 +658,7 @@
 			HvCallHpt_setPp(slot, PP_RWXX);
 		} else
 			/* No HPTE exists, so create a new bolted one */
-			iSeries_make_pte(va, (unsigned long)__v2a(ea),
-					mode_rw);
+			iSeries_make_pte(va, phys_to_abs(pa), mode_rw);
 	}
 }
 
@@ -728,29 +722,6 @@
 			tbFreqMhzHundreths);
 	systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR;
 	printk("Processor version = %x\n", systemcfg->processor);
-}
-
-/*
- * int as400_setup_residual()
- *
- * Description:
- *   This routine pretty-prints CPU information gathered from the VPD    
- *   for use in /proc/cpuinfo                               
- *
- * Input(s):
- *  *buffer - Buffer into which CPU data is to be printed.             
- *
- * Output(s):
- *  *buffer - Buffer with CPU data.
- */
-void iSeries_setup_residual(struct seq_file *m, int cpu_id)
-{
-	seq_printf(m, "clock\t\t: %lu.%02luMhz\n", procFreqMhz,
-			procFreqMhzHundreths);
-	seq_printf(m, "time base\t: %lu.%02luMHz\n", tbFreqMhz,
-			tbFreqMhzHundreths);
-	seq_printf(m, "i-cache\t\t: %d\n", systemcfg->iCacheL1LineSize);
-	seq_printf(m, "d-cache\t\t: %d\n", systemcfg->dCacheL1LineSize);
 }
 
 void iSeries_get_cpuinfo(struct seq_file *m)
diff -Nru a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
--- a/arch/ppc64/kernel/idle.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/kernel/idle.c	Sat Apr  3 19:38:55 2004
@@ -172,16 +172,16 @@
 		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
 		if (!oldval) {
 			set_thread_flag(TIF_POLLING_NRFLAG);
-			start_snooze = __get_tb();
+			start_snooze = __get_tb() +
+				naca->smt_snooze_delay*tb_ticks_per_usec;
 			while (!need_resched()) {
 				/* need_resched could be 1 or 0 at this 
 				 * point.  If it is 0, set it to 0, so
 				 * an IPI/Prod is sent.  If it is 1, keep
 				 * it that way & schedule work.
 				 */
-				if (__get_tb() < 
-				    (start_snooze + 
-				     naca->smt_snooze_delay*tb_ticks_per_usec)) {  
+				if (naca->smt_snooze_delay == 0 ||
+				    __get_tb() < start_snooze) {
 					HMT_low(); /* Low thread priority */
 					continue;
 				}
diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c
--- a/arch/ppc64/kernel/ioctl32.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc64/kernel/ioctl32.c	Sat Apr  3 19:38:56 2004
@@ -346,9 +346,6 @@
 COMPATIBLE_IOCTL(TIOCSTART)
 COMPATIBLE_IOCTL(TIOCSTOP)
 COMPATIBLE_IOCTL(TIOCSLTC)
-#if 0
-COMPATIBLE_IOCTL(FBIOBLANK)
-#endif
 /* Little p (/dev/rtc, /dev/envctrl, etc.) */
 COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
 COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
diff -Nru a/arch/ppc64/kernel/iommu.c b/arch/ppc64/kernel/iommu.c
--- a/arch/ppc64/kernel/iommu.c	Sat Apr  3 19:38:40 2004
+++ b/arch/ppc64/kernel/iommu.c	Sat Apr  3 19:38:40 2004
@@ -32,6 +32,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/init.h>
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -73,7 +74,7 @@
 	if (unlikely(npages) == 0) {
 		if (printk_ratelimit())
 			WARN_ON(1);
-		return NO_TCE;
+		return DMA_ERROR_CODE;
 	}
 
 	if (handle && *handle)
@@ -100,16 +101,17 @@
 	end = n + npages;
 
 	if (unlikely(end >= limit)) {
-		if (likely(pass++ < 2)) {
+		if (likely(pass < 2)) {
 			/* First failure, just rescan the half of the table.
 			 * Second failure, rescan the other half of the table.
 			 */
 			start = (largealloc ^ pass) ? tbl->it_halfpoint : 0;
 			limit = pass ? tbl->it_mapsize : limit;
+			pass++;
 			goto again;
 		} else {
 			/* Third failure, give up */
-			return NO_TCE;
+			return DMA_ERROR_CODE;
 		}
 	}
 
@@ -143,15 +145,15 @@
 		       unsigned int npages, int direction)
 {
 	unsigned long entry, flags;
-	dma_addr_t ret = NO_TCE;
+	dma_addr_t ret = DMA_ERROR_CODE;
 	
 	spin_lock_irqsave(&(tbl->it_lock), flags);
 
 	entry = iommu_range_alloc(tbl, npages, NULL);
 
-	if (unlikely(entry == NO_TCE)) {
+	if (unlikely(entry == DMA_ERROR_CODE)) {
 		spin_unlock_irqrestore(&(tbl->it_lock), flags);
-		return NO_TCE;
+		return DMA_ERROR_CODE;
 	}
 
 	entry += tbl->it_offset;	/* Offset into real TCE table */
@@ -262,7 +264,7 @@
 		DBG("  - vaddr: %lx, size: %lx\n", vaddr, slen);
 
 		/* Handle failure */
-		if (unlikely(entry == NO_TCE)) {
+		if (unlikely(entry == DMA_ERROR_CODE)) {
 			if (printk_ratelimit())
 				printk(KERN_INFO "iommu_alloc failed, tbl %p vaddr %lx"
 				       " npages %lx\n", tbl, vaddr, npages);
@@ -326,7 +328,7 @@
 	 */
 	if (outcount < nelems) {
 		outs++;
-		outs->dma_address = NO_TCE;
+		outs->dma_address = DMA_ERROR_CODE;
 		outs->dma_length = 0;
 	}
 	return outcount;
diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
--- a/arch/ppc64/kernel/irq.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/kernel/irq.c	Sat Apr  3 19:38:43 2004
@@ -66,7 +66,7 @@
 		.lock = SPIN_LOCK_UNLOCKED
 	}
 };
-	
+
 int ppc_spurious_interrupts = 0;
 unsigned long lpEvent_count = 0;
 
@@ -183,6 +183,7 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 	} 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 @@
 	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 @@
 		return;
 
 	once++;
-	
+
 	ppc_md.init_IRQ();
 }
 
@@ -699,6 +704,7 @@
 {
 	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 @@
 		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.
@@ -899,5 +913,38 @@
 	}
 	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 -Nru a/arch/ppc64/kernel/mf.c b/arch/ppc64/kernel/mf.c
--- a/arch/ppc64/kernel/mf.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc64/kernel/mf.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 	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 @@
 	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 @@
 
 	/* 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)
@@ -763,14 +763,10 @@
 	ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
 	ev->event.data.vsp_cmd.result_code = 0xFF;
 	ev->event.data.vsp_cmd.reserved = 0;
-	ev->event.data.vsp_cmd.sub_data.page[0] =
-		(0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[0]));
-	ev->event.data.vsp_cmd.sub_data.page[1] =
-		(0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[1]));
-	ev->event.data.vsp_cmd.sub_data.page[2] =
-		(0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[2]));
-	ev->event.data.vsp_cmd.sub_data.page[3] =
-		(0x8000000000000000ULL | virt_to_absolute((unsigned long)pages[3]));
+	ev->event.data.vsp_cmd.sub_data.page[0] = ISERIES_HV_ADDR(pages[0]);
+	ev->event.data.vsp_cmd.sub_data.page[1] = ISERIES_HV_ADDR(pages[1]);
+	ev->event.data.vsp_cmd.sub_data.page[2] = ISERIES_HV_ADDR(pages[2]);
+	ev->event.data.vsp_cmd.sub_data.page[3] = ISERIES_HV_ADDR(pages[3]);
 	mb();
 	if (signal_event(ev) != 0)
 		return;
diff -Nru a/arch/ppc64/kernel/mf_proc.c b/arch/ppc64/kernel/mf_proc.c
--- a/arch/ppc64/kernel/mf_proc.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/kernel/mf_proc.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	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 @@
 
 		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 @@
 
 	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 @@
 
 	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 -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/kernel/misc.S	Sat Apr  3 19:38:55 2004
@@ -565,35 +565,6 @@
 	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
@@ -622,7 +593,7 @@
 	.llong .sys_ni_syscall		/* old stat syscall */
 	.llong .ppc32_lseek
 	.llong .sys_getpid              /* 20 */
-	.llong .sys32_mount
+	.llong .compat_sys_mount
 	.llong .sys_oldumount
 	.llong .sys_setuid
 	.llong .sys_getuid
@@ -653,7 +624,7 @@
 	.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 -Nru a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c
--- a/arch/ppc64/kernel/pSeries_iommu.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/kernel/pSeries_iommu.c	Sat Apr  3 19:38:41 2004
@@ -44,16 +44,6 @@
 #include "pci.h"
 
 
-/* Only used to pass OF initialization data set in prom.c into the main 
- * kernel code -- data ultimately copied into regular tce tables.
- */
-extern struct _of_tce_table of_tce_table[];
-
-
-extern struct pci_controller  *hose_head;
-extern struct pci_controller **hose_tail;
-
-
 static void tce_build_pSeries(struct iommu_table *tbl, long index, 
 			      long npages, unsigned long uaddr, 
 			      int direction)
@@ -71,7 +61,7 @@
 
 	while (npages--) {
 		/* can't move this out since we might cross LMB boundary */
-		t.te_rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+		t.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT;
 	
 		tp->te_word = t.te_word;
 
@@ -97,13 +87,23 @@
 }
 
 
-
 static void iommu_buses_init(void)
 {
 	struct pci_controller* phb;
 	struct device_node *dn, *first_dn;
 	int num_slots, num_slots_ilog2;
 	int first_phb = 1;
+	unsigned long tcetable_ilog2;
+
+	/*
+	 * We default to a TCE table that maps 2GB (4MB table, 22 bits),
+	 * however some machines have a 3GB IO hole and for these we
+	 * create a table that maps 1GB (2MB table, 21 bits)
+	 */
+	if (io_hole_start < 0x80000000UL)
+		tcetable_ilog2 = 21;
+	else
+		tcetable_ilog2 = 22;
 
 	/* XXX Should we be using pci_root_buses instead?  -ojn 
 	 */
@@ -119,7 +119,7 @@
 		if ((1<<num_slots_ilog2) != num_slots)
 			num_slots_ilog2++;
 
-		phb->dma_window_size = 1 << (22 - num_slots_ilog2);
+		phb->dma_window_size = 1 << (tcetable_ilog2 - num_slots_ilog2);
 
 		/* Reserve 16MB of DMA space on the first PHB.
 		 * We should probably be more careful and use firmware props.
@@ -167,7 +167,7 @@
 {
 	phandle node;
 	unsigned long i;
-	struct _of_tce_table *oft;
+	struct of_tce_table *oft;
 
 	node = ((struct device_node *)(phb->arch_data))->node;
 
diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
--- a/arch/ppc64/kernel/pSeries_lpar.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc64/kernel/pSeries_lpar.c	Sat Apr  3 19:38:56 2004
@@ -36,6 +36,13 @@
 #include <asm/tlb.h>
 #include <asm/hvcall.h>
 #include <asm/prom.h>
+#include <asm/abs_addr.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)
 {
@@ -129,7 +136,7 @@
 	union tce_entry tce;
 
 	tce.te_word = 0;
-	tce.te_rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+	tce.te_rpn = (virt_to_abs(uaddr)) >> PAGE_SHIFT;
 	tce.te_rdwr = 1;
 	if (direction != PCI_DMA_TODEVICE)
 		tce.te_pciwr = 1;
diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c
--- a/arch/ppc64/kernel/pSeries_pci.c	Sat Apr  3 19:38:57 2004
+++ b/arch/ppc64/kernel/pSeries_pci.c	Sat Apr  3 19:38:57 2004
@@ -699,7 +699,8 @@
 	phbs_fixup_io();
 	chrp_request_regions();
 	pci_fix_bus_sysdata();
-	iommu_setup_pSeries();
+	if (!ppc64_iommu_off)
+		iommu_setup_pSeries();
 }
 
 /*********************************************************************** 
diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/kernel/pci.c	Sat Apr  3 19:38:55 2004
@@ -119,43 +119,6 @@
 	}
 }
 
-/* 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)
@@ -358,6 +321,10 @@
 
 	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 -Nru a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h
--- a/arch/ppc64/kernel/pci.h	Sat Apr  3 19:38:40 2004
+++ b/arch/ppc64/kernel/pci.h	Sat Apr  3 19:38:40 2004
@@ -37,11 +37,14 @@
 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 -Nru a/arch/ppc64/kernel/pci_dma_direct.c b/arch/ppc64/kernel/pci_dma_direct.c
--- a/arch/ppc64/kernel/pci_dma_direct.c	Sat Apr  3 19:38:40 2004
+++ b/arch/ppc64/kernel/pci_dma_direct.c	Sat Apr  3 19:38:40 2004
@@ -37,7 +37,7 @@
 	ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
 	if (ret != NULL) {
 		memset(ret, 0, size);
-		*dma_handle = virt_to_absolute((unsigned long)ret);
+		*dma_handle = virt_to_abs(ret);
 	}
 	return ret;
 }
@@ -51,7 +51,7 @@
 static dma_addr_t pci_direct_map_single(struct pci_dev *hwdev, void *ptr,
 				  size_t size, int direction)
 {
-	return virt_to_absolute((unsigned long)ptr);
+	return virt_to_abs(ptr);
 }
 
 static void pci_direct_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
diff -Nru a/arch/ppc64/kernel/pci_iommu.c b/arch/ppc64/kernel/pci_iommu.c
--- a/arch/ppc64/kernel/pci_iommu.c	Sat Apr  3 19:38:45 2004
+++ b/arch/ppc64/kernel/pci_iommu.c	Sat Apr  3 19:38:45 2004
@@ -31,6 +31,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/iommu.h>
@@ -82,7 +83,7 @@
 	if (order >= IOMAP_MAX_ORDER) {
 		printk("PCI_DMA: pci_alloc_consistent size too large: 0x%lx\n",
 			size);
-		return (void *)NO_TCE;
+		return (void *)DMA_ERROR_CODE;
 	}
 
 	tbl = devnode_table(hwdev); 
@@ -101,7 +102,7 @@
 	/* Set up tces to cover the allocated range */
 	mapping = iommu_alloc(tbl, ret, npages, PCI_DMA_BIDIRECTIONAL);
 
-	if (mapping == NO_TCE) {
+	if (mapping == DMA_ERROR_CODE) {
 		free_pages((unsigned long)ret, order);
 		ret = NULL;
 	} else
@@ -139,7 +140,7 @@
 				size_t size, int direction)
 {
 	struct iommu_table * tbl;
-	dma_addr_t dma_handle = NO_TCE;
+	dma_addr_t dma_handle = DMA_ERROR_CODE;
 	unsigned long uaddr;
 	unsigned int npages;
 
@@ -153,7 +154,7 @@
 
 	if (tbl) {
 		dma_handle = iommu_alloc(tbl, vaddr, npages, direction);
-		if (dma_handle == NO_TCE) {
+		if (dma_handle == DMA_ERROR_CODE) {
 			if (printk_ratelimit())  {
 				printk(KERN_INFO "iommu_alloc failed, tbl %p vaddr %p npages %d\n",
 				       tbl, vaddr, npages);
diff -Nru a/arch/ppc64/kernel/pmac_iommu.c b/arch/ppc64/kernel/pmac_iommu.c
--- a/arch/ppc64/kernel/pmac_iommu.c	Sat Apr  3 19:38:56 2004
+++ b/arch/ppc64/kernel/pmac_iommu.c	Sat Apr  3 19:38:56 2004
@@ -154,7 +154,7 @@
 	 * out of the loop.
 	 */
 	while (npages--) {
-		rpn = (virt_to_absolute(uaddr)) >> PAGE_SHIFT;
+		rpn = virt_to_abs(uaddr) >> PAGE_SHIFT;
 
 		*(dp++) = DARTMAP_VALID | (rpn & DARTMAP_RPNMASK);
 
@@ -210,7 +210,7 @@
 	if (tmp == 0)
 		panic("U3-DART: Cannot allocate spare page !");
 	dart_emptyval = DARTMAP_VALID |
-		((virt_to_absolute(tmp) >> PAGE_SHIFT) & DARTMAP_RPNMASK);
+		((virt_to_abs(tmp) >> PAGE_SHIFT) & DARTMAP_RPNMASK);
 
 	/* Map in DART registers. FIXME: Use device node to get base address */
 	dart = ioremap(DART_BASE, 0x7000);
@@ -225,7 +225,7 @@
 		(((dart_tablesize >> PAGE_SHIFT) & DARTCNTL_SIZE_MASK)
 				 << DARTCNTL_SIZE_SHIFT);
 	p = virt_to_page(dart_tablebase);
-	dart_vbase = ioremap(virt_to_absolute(dart_tablebase), dart_tablesize);
+	dart_vbase = ioremap(virt_to_abs(dart_tablebase), dart_tablesize);
 
 	/* Fill initial table */
 	for (i = 0; i < dart_tablesize/4; i++)
@@ -289,8 +289,11 @@
 	 * things simple. Setup all PCI devices to point to this table
 	 */
 	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		dn = PCI_GET_DN(dev);
-
+		/* We must use pci_device_to_OF_node() to make sure that
+		 * we get the real "final" pointer to the device in the
+		 * pci_dev sysdata and not the temporary PHB one
+		 */
+		struct device_node *dn = pci_device_to_OF_node(dev);
 		if (dn)
 			dn->iommu_table = &iommu_table_pmac;
 	}
diff -Nru a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c
--- a/arch/ppc64/kernel/pmac_setup.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/kernel/pmac_setup.c	Sat Apr  3 19:38:41 2004
@@ -95,7 +95,6 @@
 					PMAC_MB_INFO_MODEL, 0);
 	unsigned int mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL,
 						 PMAC_MB_INFO_FLAGS, 0);
-	extern unsigned long ppc_tb_freq;
 
 	if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME,
 			      (long)&mbname) != 0)
@@ -130,9 +129,6 @@
 
 	/* Indicate newworld */
 	seq_printf(m, "pmac-generation\t: NewWorld\n");
-
-	/* Indicate timebase value */
-	seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq);
 }
 
 
diff -Nru a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c
--- a/arch/ppc64/kernel/pmac_smp.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/kernel/pmac_smp.c	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c
--- a/arch/ppc64/kernel/pmac_time.c	Sat Apr  3 19:38:45 2004
+++ b/arch/ppc64/kernel/pmac_time.c	Sat Apr  3 19:38:45 2004
@@ -40,6 +40,7 @@
 extern void setup_default_decr(void);
 
 extern unsigned long ppc_tb_freq;
+extern unsigned long ppc_proc_freq;
 
 /* Apparently the RTC stores seconds since 1 Jan 1904 */
 #define RTC_OFFSET	2082844800
@@ -154,6 +155,11 @@
 	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
 	tb_to_xs = divres.result_low;
 	ppc_tb_freq = freq;
+
+	fp = (unsigned int *)get_property(cpu, "clock-frequency", NULL);
+	if (fp == 0)
+		panic("can't get cpu processor frequency");
+	ppc_proc_freq = *fp;
 
 	setup_default_decr();
 }
diff -Nru a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c
--- a/arch/ppc64/kernel/pmc.c	Sat Apr  3 19:38:45 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
--- a/arch/ppc64/kernel/ppc_ksyms.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc64/kernel/ppc_ksyms.c	Sat Apr  3 19:38:42 2004
@@ -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(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(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(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(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(tb_ticks_per_usec);
 EXPORT_SYMBOL(paca);
-EXPORT_SYMBOL(proc_ppc64);
+EXPORT_SYMBOL(cur_cpu_spec);
+EXPORT_SYMBOL(systemcfg);
diff -Nru a/arch/ppc64/kernel/proc_pmc.c b/arch/ppc64/kernel/proc_pmc.c
--- a/arch/ppc64/kernel/proc_pmc.c	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/arch/ppc64/kernel/proc_ppc64.c b/arch/ppc64/kernel/proc_ppc64.c
--- a/arch/ppc64/kernel/proc_ppc64.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc64/kernel/proc_ppc64.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 #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 @@
 };
 #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 @@
 	}
 }
 
+/*
+ * 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 @@
 
 #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 @@
 
 }
 #endif	/* defined(CONFIG_PPC_PSERIES) */
-
-fs_initcall(proc_ppc64_init);
diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
--- a/arch/ppc64/kernel/process.c	Sat Apr  3 19:38:44 2004
+++ b/arch/ppc64/kernel/process.c	Sat Apr  3 19:38:44 2004
@@ -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>
@@ -160,28 +161,6 @@
 	local_irq_save(flags);
 	last = _switch(old_thread, new_thread);
 
-	/*
-	 * force our kernel stack out of the ERAT and SLB, this is to
-	 * avoid the race where we it hangs around in the ERAT but not the
-	 * SLB and the ERAT gets invalidated at just the wrong moment by
-	 * another CPU doing a tlbie.
-	 *
-	 * We definitely dont want to flush our bolted segment, so check
-	 * for that first.
-	 */
-	if ((cur_cpu_spec->cpu_features & CPU_FTR_SLB) &&
-	    GET_ESID(__get_SP()) != GET_ESID(PAGE_OFFSET)) {
-		union {
-			unsigned long word0;
-			slb_dword0 data;
-		} esid_data;
-
-		esid_data.word0 = 0;
-		/* class bit is in valid field for slbie instruction */
-		esid_data.data.v = 1;
-		esid_data.data.esid = GET_ESID(__get_SP());
-		asm volatile("isync; slbie %0; isync" : : "r" (esid_data));
-	}
 	local_irq_restore(flags);
 
 	return last;
@@ -193,8 +172,8 @@
 
 	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 -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
--- a/arch/ppc64/kernel/prom.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc64/kernel/prom.c	Sat Apr  3 19:38:54 2004
@@ -61,6 +61,14 @@
 #endif
 
 /*
+ * Properties whose value is longer than this get excluded from our
+ * copy of the device tree. This value does need to be big enough to
+ * ensure that we don't lose things like the interrupt-map property
+ * on a PCI-PCI bridge.
+ */
+#define MAX_PROPERTY_LENGTH	(1UL * 1024 * 1024)
+
+/*
  * prom_init() is called very early on, before the kernel text
  * and data have been mapped to KERNELBASE.  At this point the code
  * is running at whatever address it has been loaded at, so
@@ -138,8 +146,8 @@
 extern unsigned long klimit;
 extern struct lmb lmb;
 
-#define MAX_PHB 16 * 3  // 16 Towers * 3 PHBs/tower
-struct _of_tce_table of_tce_table[MAX_PHB + 1] = {{0, 0, 0}};
+#define MAX_PHB (32 * 6)  /* 32 drawers * 6 PHBs/drawer */
+struct of_tce_table of_tce_table[MAX_PHB + 1];
 
 char *bootpath = 0;
 char *bootdevice = 0;
@@ -517,25 +525,16 @@
 	return mem;
 }
 
-#ifdef CONFIG_PMAC_DART
-static int dart_force_on;
-#endif
+static int iommu_force_on;
+int ppc64_iommu_off;
 
-static unsigned long __init
-prom_initialize_lmb(unsigned long mem)
+static void early_cmdline_parse(void)
 {
-	phandle node;
-	char type[64];
-        unsigned long i, offset = reloc_offset();
-	struct prom_t *_prom = PTRRELOC(&prom);
-        struct systemcfg *_systemcfg = RELOC(systemcfg);
-	union lmb_reg_property reg;
-	unsigned long lmb_base, lmb_size;
-	unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8;
-	int nodart = 0;
-
-#ifdef CONFIG_PMAC_DART
+	unsigned long offset = reloc_offset();
 	char *opt;
+#ifndef CONFIG_PMAC_DART
+	struct systemcfg *_systemcfg = RELOC(systemcfg);
+#endif
 
 	opt = strstr(RELOC(cmd_line), RELOC("iommu="));
 	if (opt) {
@@ -546,16 +545,30 @@
 		while (*opt && *opt == ' ')
 			opt++;
 		if (!strncmp(opt, RELOC("off"), 3))
-			nodart = 1;
+			RELOC(ppc64_iommu_off) = 1;
 		else if (!strncmp(opt, RELOC("force"), 5))
-			RELOC(dart_force_on) = 1;
+			RELOC(iommu_force_on) = 1;
 	}
-#else
-	nodart = 1;
-#endif /* CONFIG_PMAC_DART */
 
-	if (nodart)
+#ifndef CONFIG_PMAC_DART
+	if (_systemcfg->platform == PLATFORM_POWERMAC) {
+		RELOC(ppc64_iommu_off) = 1;
 		prom_print(RELOC("DART disabled on PowerMac !\n"));
+	}
+#endif
+}
+
+static unsigned long __init
+prom_initialize_lmb(unsigned long mem)
+{
+	phandle node;
+	char type[64];
+        unsigned long i, offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
+	union lmb_reg_property reg;
+	unsigned long lmb_base, lmb_size;
+	unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8;
 
 	lmb_init();
 
@@ -581,11 +594,6 @@
 				lmb_base = ((unsigned long)reg.addrPM[i].address_hi) << 32;
 				lmb_base |= (unsigned long)reg.addrPM[i].address_lo;
 				lmb_size = reg.addrPM[i].size;
-				if (nodart && lmb_base > 0x80000000ull) {
-					prom_print(RELOC("Skipping memory above 2Gb for "
-							 "now, DART support disabled\n"));
-					continue;
-				}
 			} else if (_prom->encode_phys_size == 32) {
 				lmb_base = reg.addr32[i].address;
 				lmb_size = reg.addr32[i].size;
@@ -594,7 +602,16 @@
 				lmb_size = reg.addr64[i].size;
 			}
 
-			if ( lmb_add(lmb_base, lmb_size) < 0 )
+			/* We limit memory to 2GB if the IOMMU is off */
+			if (RELOC(ppc64_iommu_off)) {
+				if (lmb_base >= 0x80000000UL)
+					continue;
+
+				if ((lmb_base + lmb_size) > 0x80000000UL)
+					lmb_size = 0x80000000UL - lmb_base;
+			}
+
+			if (lmb_add(lmb_base, lmb_size) < 0)
 				prom_print(RELOC("Too many LMB's, discarding this one...\n"));
 		}
 
@@ -772,11 +789,11 @@
 	/* Only reserve DART space if machine has more than 2GB of RAM
 	 * or if requested with iommu=on on cmdline.
 	 */
-	if (lmb_end_of_DRAM() <= 0x80000000ull && !RELOC(dart_force_on))
+	if (lmb_end_of_DRAM() <= 0x80000000ull && !RELOC(iommu_force_on))
 		return;
 
-	/* 512 pages is max DART tablesize. */
-	RELOC(dart_tablesize) = 1UL << 19;
+	/* 512 pages (2MB) is max DART tablesize. */
+	RELOC(dart_tablesize) = 1UL << 21;
 	/* 16MB (1 << 24) alignment. We allocate a full 16Mb chuck since we
 	 * will blow up an entire large page anyway in the kernel mapping
 	 */
@@ -800,15 +817,24 @@
 	unsigned long i, table = 0;
 	unsigned long base, vbase, align;
 	unsigned int minalign, minsize;
-	struct _of_tce_table *prom_tce_table = RELOC(of_tce_table);
+	struct of_tce_table *prom_tce_table = RELOC(of_tce_table);
 	unsigned long tce_entry, *tce_entryp;
 
+	if (RELOC(ppc64_iommu_off))
+		return;
+
 #ifdef DEBUG_PROM
 	prom_print(RELOC("starting prom_initialize_tce_table\n"));
 #endif
 
 	/* Search all nodes looking for PHBs. */
 	for (node = 0; prom_next_node(&node); ) {
+		if (table == MAX_PHB) {
+			prom_print(RELOC("WARNING: PCI host bridge ignored, "
+				         "need to increase MAX_PHB\n"));
+			continue;
+		}
+
 		compatible[0] = 0;
 		type[0] = 0;
 		model[0] = 0;
@@ -848,20 +874,21 @@
 			minsize = 4UL << 20;
 		}
 
-		/* Even though we read what OF wants, we just set the table
+		/*
+		 * Even though we read what OF wants, we just set the table
 		 * size to 4 MB.  This is enough to map 2GB of PCI DMA space.
 		 * By doing this, we avoid the pitfalls of trying to DMA to
 		 * MMIO space and the DMA alias hole.
-		 */
-		/* 
+		 *
 		 * On POWER4, firmware sets the TCE region by assuming
 		 * each TCE table is 8MB. Using this memory for anything
 		 * else will impact performance, so we always allocate 8MB.
 		 * Anton
-		 *
-		 * XXX FIXME use a cpu feature here
 		 */
-		minsize = 8UL << 20;
+		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p))
+			minsize = 8UL << 20;
+		else
+			minsize = 4UL << 20;
 
 		/* Align to the greater of the align or size */
 		align = max(minalign, minsize);
@@ -873,7 +900,7 @@
 			prom_panic(RELOC("ERROR, cannot find space for TCE table.\n"));
 		}
 
-		vbase = absolute_to_virt(base);
+		vbase = (unsigned long)abs_to_virt(base);
 
 		/* Save away the TCE table attributes for later use. */
 		prom_tce_table[table].node = node;
@@ -908,21 +935,22 @@
 			*tce_entryp = tce_entry;
 		}
 
+		/* It seems OF doesn't null-terminate the path :-( */
+		memset(path, 0, sizeof(path));
 		/* Call OF to setup the TCE hardware */
 		if (call_prom(RELOC("package-to-path"), 3, 1, node,
-                             path, 255) <= 0) {
+                             path, sizeof(path)-1) <= 0) {
                         prom_print(RELOC("package-to-path failed\n"));
                 } else {
-                        prom_print(RELOC("opened "));
+                        prom_print(RELOC("opening PHB "));
                         prom_print(path);
-                        prom_print_nl();
                 }
 
                 phb_node = (ihandle)call_prom(RELOC("open"), 1, 1, path);
                 if ( (long)phb_node <= 0) {
-                        prom_print(RELOC("open failed\n"));
+                        prom_print(RELOC("... failed\n"));
                 } else {
-                        prom_print(RELOC("open success\n"));
+                        prom_print(RELOC("... done\n"));
                 }
                 call_prom(RELOC("call-method"), 6, 0,
                              RELOC("set-64-bit-addressing"),
@@ -979,9 +1007,12 @@
 	extern void __secondary_hold(void);
         extern unsigned long __secondary_hold_spinloop;
         extern unsigned long __secondary_hold_acknowledge;
-        unsigned long *spinloop     = __v2a(&__secondary_hold_spinloop);
-        unsigned long *acknowledge  = __v2a(&__secondary_hold_acknowledge);
-        unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
+        unsigned long *spinloop
+		= (void *)virt_to_abs(&__secondary_hold_spinloop);
+        unsigned long *acknowledge
+		= (void *)virt_to_abs(&__secondary_hold_acknowledge);
+        unsigned long secondary_hold
+		= virt_to_abs(*PTRRELOC((unsigned long *)__secondary_hold));
         struct systemcfg *_systemcfg = RELOC(systemcfg);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
@@ -1119,7 +1150,7 @@
 			prom_print_hex(cpuid);
 			prom_print(RELOC(" : starting cpu "));
 			prom_print(path);
-			prom_print(RELOC("..."));
+			prom_print(RELOC("... "));
 			call_prom(RELOC("start-cpu"), 3, 0, node, 
 				  secondary_hold, cpuid);
 
@@ -1127,7 +1158,7 @@
 			      (*acknowledge == ((unsigned long)-1)); i++ ) ;
 
 			if (*acknowledge == cpuid) {
-				prom_print(RELOC("ok\n"));
+				prom_print(RELOC("... done\n"));
 				/* We have to get every CPU out of OF,
 				 * even if we never start it. */
 				if (cpuid >= NR_CPUS)
@@ -1140,10 +1171,9 @@
 				cpu_set(cpuid, RELOC(cpu_present_at_boot));
 #endif
 			} else {
-				prom_print(RELOC("failed: "));
+				prom_print(RELOC("... failed: "));
 				prom_print_hex(*acknowledge);
 				prom_print_nl();
-				/* prom_panic(RELOC("cpu failed to start")); */
 			}
 		}
 #ifdef CONFIG_SMP
@@ -1566,6 +1596,8 @@
 			strlcpy(RELOC(cmd_line), p, sizeof(cmd_line));
 	}
 
+	early_cmdline_parse();
+
 	mem = prom_initialize_lmb(mem);
 
 	mem = prom_bi_rec_reserve(mem);
@@ -1674,7 +1706,7 @@
 
 	prom_print(RELOC("Looking for displays\n"));
 	if (RELOC(of_stdout_device) != 0) {
-		prom_print(RELOC("OF stdout is   : "));
+		prom_print(RELOC("OF stdout is    : "));
 		prom_print(PTRRELOC(RELOC(of_stdout_device)));
 		prom_print(RELOC("\n"));
 	}
@@ -1687,6 +1719,11 @@
 		/* It seems OF doesn't null-terminate the path :-( */
 		path = (char *) mem;
 		memset(path, 0, 256);
+
+		/*
+		 * leave some room at the end of the path for appending extra
+		 * arguments
+		 */
 		if ((long) call_prom(RELOC("package-to-path"), 3, 1,
 				    node, path, 250) < 0)
 			continue;
@@ -1729,7 +1766,7 @@
 			continue;
 		}
 
-		prom_print(RELOC("... ok\n"));
+		prom_print(RELOC("... done\n"));
 
 		/* Setup a useable color table when the appropriate
 		 * method is available. Should update this to set-colors */
@@ -1794,8 +1831,7 @@
 	return new_start;
 }
 
-__init
-static unsigned long
+static unsigned long __init
 inspect_node(phandle node, struct device_node *dad,
 	     unsigned long mem_start, unsigned long mem_end,
 	     struct device_node ***allnextpp)
@@ -1843,6 +1879,22 @@
 				  valp, mem_end - mem_start);
 		if (pp->length < 0)
 			continue;
+		if (pp->length > MAX_PROPERTY_LENGTH) {
+			char path[128];
+
+			prom_print(RELOC("WARNING: ignoring large property "));
+			/* It seems OF doesn't null-terminate the path :-( */
+			memset(path, 0, sizeof(path));
+			if (call_prom(RELOC("package-to-path"), 3, 1, node,
+                            path, sizeof(path)-1) > 0)
+				prom_print(path);
+			prom_print(namep);
+			prom_print(RELOC(" length 0x"));
+			prom_print_hex(pp->length);
+			prom_print_nl();
+
+			continue;
+		}
 		mem_start = DOUBLEWORD_ALIGN(mem_start + pp->length);
 		*prev_propp = PTRUNRELOC(pp);
 		prev_propp = &pp->next;
@@ -2853,40 +2905,12 @@
 	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 +2988,53 @@
 #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 +3049,8 @@
 {
 	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 +3066,10 @@
 	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 +3099,9 @@
 	}
 
 	/* 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 -Nru a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c
--- a/arch/ppc64/kernel/ras.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc64/kernel/ras.c	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c
--- a/arch/ppc64/kernel/rtas-proc.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/kernel/rtas-proc.c	Sat Apr  3 19:38:43 2004
@@ -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,50 +198,49 @@
 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;
 
+	if (!(systemcfg->platform & PLATFORM_PSERIES))
+		return 1;
+
 	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;
-
-	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;
+	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 -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c
--- a/arch/ppc64/kernel/rtas.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/kernel/rtas.c	Sat Apr  3 19:38:41 2004
@@ -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>
@@ -131,7 +130,7 @@
 void
 log_rtas_error(struct rtas_args	*rtas_args)
 {
-	struct rtas_args err_args;
+	struct rtas_args err_args, temp_args;
 
 	err_args.token = rtas_token("rtas-last-error");
 	err_args.nargs = 2;
@@ -142,6 +141,7 @@
 	err_args.args[1] = RTAS_ERROR_LOG_MAX;
 	err_args.args[2] = 0;
 
+	temp_args = *rtas_args;
 	get_paca()->xRtas = err_args;
 
 	PPCDBG(PPCDBG_RTAS, "\tentering rtas with 0x%lx\n",
@@ -149,8 +149,9 @@
 	enter_rtas((void *)__pa((unsigned long)&get_paca()->xRtas));
 	PPCDBG(PPCDBG_RTAS, "\treturned from rtas ...\n");
 
+
 	err_args = get_paca()->xRtas;
-	get_paca()->xRtas = *rtas_args;
+	get_paca()->xRtas = temp_args;
 
 	if (err_args.rets[0] == 0)
 		log_error(rtas_err_buf, ERR_TYPE_RTAS_LOG, 0);
@@ -259,6 +260,33 @@
 }
 
 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");
@@ -333,7 +361,7 @@
 	 */
 	rtas_firmware_flash_list.num_blocks = 0;
 	flist = (struct flash_block_list *)&rtas_firmware_flash_list;
-	rtas_block_list = virt_to_absolute((unsigned long)flist);
+	rtas_block_list = virt_to_abs(flist);
 	if (rtas_block_list >= (4UL << 20)) {
 		printk(KERN_ALERT "FLASH: kernel bug...flash list header addr above 4GB\n");
 		return;
@@ -345,13 +373,13 @@
 	for (f = flist; f; f = next) {
 		/* Translate data addrs to absolute */
 		for (i = 0; i < f->num_blocks; i++) {
-			f->blocks[i].data = (char *)virt_to_absolute((unsigned long)f->blocks[i].data);
+			f->blocks[i].data = (char *)virt_to_abs(f->blocks[i].data);
 			image_size += f->blocks[i].length;
 		}
 		next = f->next;
 		/* Don't translate NULL pointer for last entry */
-		if(f->next)
-			f->next = (struct flash_block_list *)virt_to_absolute((unsigned long)f->next);
+		if (f->next)
+			f->next = (struct flash_block_list *)virt_to_abs(f->next);
 		else
 			f->next = 0LL;
 		/* make num_blocks into the version/length field */
@@ -426,6 +454,7 @@
 {
 	struct rtas_args args;
 	unsigned long flags;
+	int nargs;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -433,14 +462,15 @@
 	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 +479,15 @@
 	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 +503,5 @@
 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 -Nru a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c
--- a/arch/ppc64/kernel/rtas_flash.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/kernel/rtas_flash.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 };
 
 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_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 @@
 	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 @@
 
 	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 @@
 	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 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 -Nru a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c
--- a/arch/ppc64/kernel/rtasd.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc64/kernel/rtasd.c	Sat Apr  3 19:38:42 2004
@@ -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_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 @@
 {
 	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 -Nru a/arch/ppc64/kernel/scanlog.c b/arch/ppc64/kernel/scanlog.c
--- a/arch/ppc64/kernel/scanlog.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/kernel/scanlog.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 		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 -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
--- a/arch/ppc64/kernel/setup.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/kernel/setup.c	Sat Apr  3 19:38:43 2004
@@ -330,6 +330,7 @@
 	unsigned short min;
 
 	if (cpu_id == NR_CPUS) {
+		seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq);
 
 		if (ppc_md.get_cpuinfo != NULL)
 			ppc_md.get_cpuinfo(m);
@@ -363,29 +364,12 @@
 
 	seq_printf(m, "\n");
 
-#ifdef CONFIG_PPC_PSERIES
 	/*
 	 * Assume here that all clock rates are the same in a
 	 * smp system.  -- Cort
 	 */
-	if (systemcfg->platform != PLATFORM_ISERIES_LPAR) {
-		struct device_node *cpu_node;
-		int *fp;
-
-		cpu_node = of_find_node_by_type(NULL, "cpu");
-		if (cpu_node) {
-			fp = (int *) get_property(cpu_node, "clock-frequency",
-						  NULL);
-			if (fp)
-				seq_printf(m, "clock\t\t: %dMHz\n",
-					   *fp / 1000000);
-			of_node_put(cpu_node);
-		}
-	}
-#endif
-
-	if (ppc_md.setup_residual != NULL)
-		ppc_md.setup_residual(m, cpu_id);
+	seq_printf(m, "clock\t\t: %lu.%06luMHz\n", ppc_proc_freq / 1000000,
+		   ppc_proc_freq % 1000000);
 
 	seq_printf(m, "revision\t: %hd.%hd\n\n", maj, min);
 	
diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c
--- a/arch/ppc64/kernel/smp.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc64/kernel/smp.c	Sat Apr  3 19:38:54 2004
@@ -629,7 +629,7 @@
 		tmp = &stab_array[PAGE_SIZE * cpu];
 		memset(tmp, 0, PAGE_SIZE); 
 		paca[cpu].xStab_data.virt = (unsigned long)tmp;
-		paca[cpu].xStab_data.real = (unsigned long)__v2a(tmp);
+		paca[cpu].xStab_data.real = virt_to_abs(tmp);
 	}
 
 	/* create a process for the processor */
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	Sat Apr  3 19:38:54 2004
+++ b/arch/ppc64/kernel/sys_ppc32.c	Sat Apr  3 19:38:54 2004
@@ -35,9 +35,6 @@
 #include <linux/uio.h>
 #include <linux/aio.h>
 #include <linux/nfs_fs.h>
-#include <linux/smb_fs.h>
-#include <linux/smb_mount.h>
-#include <linux/ncp_fs.h>
 #include <linux/module.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
@@ -253,209 +250,6 @@
 	return ret;
 }
 
-struct ncp_mount_data32_v3 {
-        int version;
-        unsigned int ncp_fd;
-        compat_uid_t mounted_uid;
-        compat_pid_t wdog_pid;
-        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
-        unsigned int time_out;
-        unsigned int retry_count;
-        unsigned int flags;
-        compat_uid_t uid;
-        compat_gid_t gid;
-        compat_mode_t file_mode;
-        compat_mode_t dir_mode;
-};
-
-struct ncp_mount_data32_v4 {
-	int version;
-	/* all members below are "long" in ABI ... i.e. 32bit on sparc32, while 64bits on sparc64 */
-	unsigned int flags;
-	unsigned int mounted_uid;
-	int wdog_pid;
-
-	unsigned int ncp_fd;
-	unsigned int time_out;
-	unsigned int retry_count;
-
-	unsigned int uid;
-	unsigned int gid;
-	unsigned int file_mode;
-	unsigned int dir_mode;
-};
-
-static void *do_ncp_super_data_conv(void *raw_data)
-{
-	switch (*(int*)raw_data) {
-		case NCP_MOUNT_VERSION:
-			{
-				struct ncp_mount_data news, *n = &news; 
-				struct ncp_mount_data32_v3 *n32 = (struct ncp_mount_data32_v3 *)raw_data;
-
-				n->version = n32->version;
-				n->ncp_fd = n32->ncp_fd;
-				n->mounted_uid = n32->mounted_uid;
-				n->wdog_pid = n32->wdog_pid;
-				memmove (n->mounted_vol, n32->mounted_vol, sizeof (n32->mounted_vol));
-				n->time_out = n32->time_out;
-				n->retry_count = n32->retry_count;
-				n->flags = n32->flags;
-				n->uid = n32->uid;
-				n->gid = n32->gid;
-				n->file_mode = n32->file_mode;
-				n->dir_mode = n32->dir_mode;
-				memcpy(raw_data, n, sizeof(*n)); 
-			}
-			break;
-		case NCP_MOUNT_VERSION_V4:
-			{
-				struct ncp_mount_data_v4 news, *n = &news; 
-				struct ncp_mount_data32_v4 *n32 = (struct ncp_mount_data32_v4 *)raw_data;
-
-				n->version = n32->version;
-				n->flags = n32->flags;
-				n->mounted_uid = n32->mounted_uid;
-				n->wdog_pid = n32->wdog_pid;
-				n->ncp_fd = n32->ncp_fd;
-				n->time_out = n32->time_out;
-				n->retry_count = n32->retry_count;
-				n->uid = n32->uid;
-				n->gid = n32->gid;
-				n->file_mode = n32->file_mode;
-				n->dir_mode = n32->dir_mode;
-				memcpy(raw_data, n, sizeof(*n)); 
-			}
-			break;
-		default:
-			/* do not touch unknown structures */
-			break;
-	}
-	return raw_data;
-}
-
-struct smb_mount_data32 {
-        int version;
-        compat_uid_t mounted_uid;
-        compat_uid_t uid;
-        compat_gid_t gid;
-        compat_mode_t file_mode;
-        compat_mode_t dir_mode;
-};
-
-static void *do_smb_super_data_conv(void *raw_data)
-{
-	struct smb_mount_data news, *s = &news;
-	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
-
-	if (s32->version != SMB_MOUNT_OLDVERSION)
-		goto out;
-	s->version = s32->version;
-	s->mounted_uid = s32->mounted_uid;
-	s->uid = s32->uid;
-	s->gid = s32->gid;
-	s->file_mode = s32->file_mode;
-	s->dir_mode = s32->dir_mode;
-	memcpy(raw_data, s, sizeof(struct smb_mount_data)); 
-out:
-	return raw_data;
-}
-
-static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
-{
-	int i;
-	unsigned long page;
-	struct vm_area_struct *vma;
-
-	*kernel = 0;
-	if(!user)
-		return 0;
-	vma = find_vma(current->mm, (unsigned long)user);
-	if(!vma || (unsigned long)user < vma->vm_start)
-		return -EFAULT;
-	if(!(vma->vm_flags & VM_READ))
-		return -EFAULT;
-	i = vma->vm_end - (unsigned long) user;
-	if(PAGE_SIZE <= (unsigned long) i)
-		i = PAGE_SIZE - 1;
-	if(!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
-	if(copy_from_user((void *) page, user, i)) {
-		free_page(page);
-		return -EFAULT;
-	}
-	*kernel = page;
-	return 0;
-}
-
-#define SMBFS_NAME	"smbfs"
-#define NCPFS_NAME	"ncpfs"
-
-asmlinkage long sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
-{
-	unsigned long type_page = 0;
-	unsigned long data_page = 0;
-	unsigned long dev_page = 0;
-	unsigned long dir_page = 0;
-	int err, is_smb, is_ncp;
-	
-	is_smb = is_ncp = 0;
-
-	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
-	if (err)
-		goto out;
-
-	if (!type_page) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	is_smb = !strcmp((char *)type_page, SMBFS_NAME);
-	is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
-
-	err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
-	if (err)
-		goto type_out;
-
-	err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
-	if (err)
-		goto data_out;
-
-	err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
-	if (err)
-		goto dev_out;
-
-	if (!is_smb && !is_ncp) {
-		lock_kernel();
-		err = do_mount((char*)dev_page, (char*)dir_page,
-				(char*)type_page, new_flags, (char*)data_page);
-		unlock_kernel();
-	} else {
-		if (is_ncp)
-			do_ncp_super_data_conv((void *)data_page);
-		else
-			do_smb_super_data_conv((void *)data_page);
-
-		lock_kernel();
-		err = do_mount((char*)dev_page, (char*)dir_page,
-				(char*)type_page, new_flags, (char*)data_page);
-		unlock_kernel();
-	}
-	free_page(dir_page);
-
-dev_out:
-	free_page(dev_page);
-
-data_out:
-	free_page(data_page);
-
-type_out:
-	free_page(type_page);
-
-out:
-	return err;
-}
-
 /* readdir & getdents */
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
@@ -528,39 +322,55 @@
 	int error;
 };
 
-static int
-filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino,
-		               unsigned int d_type)
+static int filldir(void * __buf, const char * name, int namlen, off_t offset,
+		   ino_t ino, unsigned int d_type)
 {
 	struct linux_dirent32 * dirent;
 	struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
-	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
 
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
 		return -EINVAL;
 	dirent = buf->previous;
-	if (dirent)
-		put_user(offset, &dirent->d_off);
+	if (dirent) {
+		if (__put_user(offset, &dirent->d_off))
+			goto efault;
+	}
 	dirent = buf->current_dir;
+	if (__put_user(ino, &dirent->d_ino))
+		goto efault;
+	if (__put_user(reclen, &dirent->d_reclen))
+		goto efault;
+	if (copy_to_user(dirent->d_name, name, namlen))
+		goto efault;
+	if (__put_user(0, dirent->d_name + namlen))
+		goto efault;
+	if (__put_user(d_type, (char *) dirent + reclen - 1))
+		goto efault;
 	buf->previous = dirent;
-	put_user(ino, &dirent->d_ino);
-	put_user(reclen, &dirent->d_reclen);
-	copy_to_user(dirent->d_name, name, namlen);
-	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *)dirent + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
+efault:
+	buf->error = -EFAULT;
+	return -EFAULT;
 }
 
-asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count)
+long sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent,
+		    unsigned int count)
 {
 	struct file * file;
 	struct linux_dirent32 * lastdirent;
 	struct getdents_callback32 buf;
-	int error = -EBADF;
+	int error;
+
+	error = -EFAULT;
+	if (!access_ok(VERIFY_WRITE, dirent, count))
+		goto out;
 
+	error = -EBADF;
 	file = fget(fd);
 	if (!file)
 		goto out;
@@ -573,19 +383,20 @@
 	error = vfs_readdir(file, (filldir_t)filldir, &buf);
 	if (error < 0)
 		goto out_putf;
-	lastdirent = buf.previous;
 	error = buf.error;
-	if(lastdirent) {
-		put_user(file->f_pos, &lastdirent->d_off);
-		error = count - buf.count;
+	lastdirent = buf.previous;
+	if (lastdirent) {
+		if (put_user(file->f_pos, &lastdirent->d_off))
+			error = -EFAULT;
+		else
+			error = count - buf.count;
 	}
- out_putf:
-	fput(file);
 
- out:
+out_putf:
+	fput(file);
+out:
 	return error;
 }
-/* end of readdir & getdents */
 
 /*
  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
@@ -2575,17 +2386,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 {
diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
--- a/arch/ppc64/kernel/traps.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/kernel/traps.c	Sat Apr  3 19:38:43 2004
@@ -511,6 +511,32 @@
 }
 #endif /* CONFIG_ALTIVEC */
 
+/*
+ * We enter here if we get an unrecoverable exception, that is, one
+ * that happened at a point where the RI (recoverable interrupt) bit
+ * in the MSR is 0.  This indicates that SRR0/1 are live, and that
+ * we therefore lost state by taking this exception.
+ */
+void unrecoverable_exception(struct pt_regs *regs)
+{
+	printk(KERN_EMERG "Unrecoverable exception %lx at %lx\n",
+	       regs->trap, regs->nip);
+	debugger(regs);
+	die("Unrecoverable exception", regs, SIGABRT);
+}
+
+/*
+ * We enter here if we discover during exception entry that we are
+ * running in supervisor mode with a userspace value in the stack pointer.
+ */
+void kernel_bad_stack(struct pt_regs *regs)
+{
+	printk(KERN_EMERG "Bad kernel stack pointer %lx at %lx\n",
+	       regs->gpr[1], regs->nip);
+	debugger(regs);
+	die("Bad kernel stack pointer", regs, SIGABRT);
+}
+
 void __init trap_init(void)
 {
 }
diff -Nru a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c
--- a/arch/ppc64/kernel/vio.c	Sat Apr  3 19:38:42 2004
+++ b/arch/ppc64/kernel/vio.c	Sat Apr  3 19:38:42 2004
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/kobject.h>
 #include <linux/mm.h>
+#include <linux/dma-mapping.h>
 #include <asm/rtas.h>
 #include <asm/iommu.h>
 #include <asm/dma.h>
@@ -419,7 +420,7 @@
 			  size_t size, int direction )
 {
 	struct iommu_table *tbl;
-	dma_addr_t dma_handle = NO_TCE;
+	dma_addr_t dma_handle = DMA_ERROR_CODE;
 	unsigned long uaddr;
 	unsigned int npages;
 
@@ -504,7 +505,7 @@
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= IOMAP_MAX_ORDER) {
  		printk("VIO_DMA: vio_alloc_consistent size to large: 0x%lx \n", size);
- 		return (void *)NO_TCE;
+ 		return (void *)DMA_ERROR_CODE;
  	}
 
 	tbl = dev->iommu_table;
@@ -517,7 +518,7 @@
 			memset(ret, 0, npages << PAGE_SHIFT);
 			/* Set up tces to cover the allocated range */
 			tce = iommu_alloc(tbl, ret, npages, PCI_DMA_BIDIRECTIONAL);
-			if (tce == NO_TCE) {
+			if (tce == DMA_ERROR_CODE) {
 				PPCDBG(PPCDBG_TCE, "vio_alloc_consistent: iommu_alloc failed\n" );
 				free_pages((unsigned long)ret, order);
 				ret = NULL;
@@ -580,5 +581,4 @@
 	.match = vio_bus_match,
 };
 
-EXPORT_SYMBOL(plpar_hcall_norets);
-EXPORT_SYMBOL(plpar_hcall_8arg_2ret);
+EXPORT_SYMBOL(vio_bus_type);
diff -Nru a/arch/ppc64/kernel/viopath.c b/arch/ppc64/kernel/viopath.c
--- a/arch/ppc64/kernel/viopath.c	Sat Apr  3 19:38:41 2004
+++ b/arch/ppc64/kernel/viopath.c	Sat Apr  3 19:38:41 2004
@@ -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>
@@ -105,6 +105,9 @@
  */
 static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES];
 
+#define VIOPATH_KERN_WARN	KERN_WARNING "viopath: "
+#define VIOPATH_KERN_INFO	KERN_INFO "viopath: "
+
 static unsigned char e2a(unsigned char x)
 {
 	switch (x) {
@@ -184,21 +187,21 @@
 	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 +209,54 @@
 			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_KERN_WARN "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);
 
-	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);
+	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]));
+
+	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
@@ -314,7 +321,7 @@
 	if (hvrc == HvLpEvent_Rc_Good)
 		viopathStatus[remoteLp].isActive = 1;
 	else {
-		printk(KERN_WARNING_VIO "could not connect to partition %d\n",
+		printk(VIOPATH_KERN_WARN "could not connect to partition %d\n",
 				remoteLp);
 		viopathStatus[remoteLp].isActive = 0;
 	}
@@ -351,11 +358,11 @@
 	remoteLp = event->xTargetLp;
 	if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) ||
 	    (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) {
-		printk(KERN_WARNING_VIO "ignoring ack....mismatched instances\n");
+		printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n");
 		return;
 	}
 
-	printk(KERN_WARNING_VIO "partition %d ended\n", remoteLp);
+	printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp);
 
 	viopathStatus[remoteLp].isActive = 0;
 
@@ -399,7 +406,7 @@
 	if (!event)
 		return;
 	if (event->xFlags.xFunction == HvLpEvent_Function_Int) {
-		printk(KERN_WARNING_VIO
+		printk(VIOPATH_KERN_WARN
 		       "unexpected config request from partition %d",
 		       event->xSourceLp);
 
@@ -433,13 +440,8 @@
 	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);
 
@@ -462,7 +464,7 @@
 		if (viopathStatus[remoteLp].isActive
 		    && (event->xSourceInstanceId !=
 			viopathStatus[remoteLp].mTargetInst)) {
-			printk(KERN_WARNING_VIO
+			printk(VIOPATH_KERN_WARN
 			       "message from invalid partition. "
 			       "int msg rcvd, source inst (%d) doesnt match (%d)\n",
 			       viopathStatus[remoteLp].mTargetInst,
@@ -473,7 +475,7 @@
 		if (viopathStatus[remoteLp].isActive
 		    && (event->xTargetInstanceId !=
 			viopathStatus[remoteLp].mSourceInst)) {
-			printk(KERN_WARNING_VIO
+			printk(VIOPATH_KERN_WARN
 			       "message from invalid partition. "
 			       "int msg rcvd, target inst (%d) doesnt match (%d)\n",
 			       viopathStatus[remoteLp].mSourceInst,
@@ -484,7 +486,7 @@
 		remoteLp = event->xTargetLp;
 		if (event->xSourceInstanceId !=
 		    viopathStatus[remoteLp].mSourceInst) {
-			printk(KERN_WARNING_VIO
+			printk(VIOPATH_KERN_WARN
 			       "message from invalid partition. "
 			       "ack msg rcvd, source inst (%d) doesnt match (%d)\n",
 			       viopathStatus[remoteLp].mSourceInst,
@@ -494,7 +496,7 @@
 
 		if (event->xTargetInstanceId !=
 		    viopathStatus[remoteLp].mTargetInst) {
-			printk(KERN_WARNING_VIO
+			printk(VIOPATH_KERN_WARN
 			       "message from invalid partition. "
 			       "viopath: ack msg rcvd, target inst (%d) doesnt match (%d)\n",
 			       viopathStatus[remoteLp].mTargetInst,
@@ -504,7 +506,7 @@
 	}
 
 	if (vio_handler[subtype] == NULL) {
-		printk(KERN_WARNING_VIO
+		printk(VIOPATH_KERN_WARN
 		       "unexpected virtual io event subtype %d from partition %d\n",
 		       event->xSubtype, remoteLp);
 		/* No handler.  Ack if necessary */
@@ -609,10 +611,10 @@
 		HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo,
 					  &vio_handleEvent);
 		sendMonMsg(remoteLp);
-		printk(KERN_INFO_VIO
-		       "Opening connection to partition %d, setting sinst %d, tinst %d\n",
-		       remoteLp, viopathStatus[remoteLp].mSourceInst,
-		       viopathStatus[remoteLp].mTargetInst);
+		printk(VIOPATH_KERN_INFO "opening connection to partition %d, "
+				"setting sinst %d, tinst %d\n",
+				remoteLp, viopathStatus[remoteLp].mSourceInst,
+				viopathStatus[remoteLp].mTargetInst);
 	}
 
 	spin_unlock_irqrestore(&statuslock, flags);
@@ -663,7 +665,7 @@
 		numOpen += viopathStatus[remoteLp].users[i];
 
 	if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) {
-		printk(KERN_INFO_VIO "Closing connection to partition %d",
+		printk(VIOPATH_KERN_INFO "closing connection to partition %d",
 				remoteLp);
 
 		HvCallEvent_closeLpEventPath(remoteLp,
@@ -697,23 +699,21 @@
 {
 	subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT;
 	if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) {
-		printk(KERN_WARNING_VIO
-		       "unexpected subtype %d freeing event buffer\n",
-		       subtype);
+		printk(VIOPATH_KERN_WARN
+		       "unexpected subtype %d freeing event buffer\n", subtype);
 		return;
 	}
 
 	if (atomic_read(&event_buffer_available[subtype]) != 0) {
-		printk(KERN_WARNING_VIO
+		printk(VIOPATH_KERN_WARN
 		       "freeing unallocated event buffer, subtype %d\n",
 		       subtype);
 		return;
 	}
 
 	if (buffer != &event_buffer[subtype * 256]) {
-		printk(KERN_WARNING_VIO
-		       "freeing invalid event buffer, subtype %d\n",
-		       subtype);
+		printk(VIOPATH_KERN_WARN
+		       "freeing invalid event buffer, subtype %d\n", subtype);
 	}
 
 	atomic_set(&event_buffer_available[subtype], 1);
diff -Nru a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c
--- a/arch/ppc64/kernel/xics.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/kernel/xics.c	Sat Apr  3 19:38:43 2004
@@ -327,6 +327,8 @@
 	}
 }
 
+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 @@
 		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 -Nru a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c
--- a/arch/ppc64/mm/hash_utils.c	Sat Apr  3 19:38:44 2004
+++ b/arch/ppc64/mm/hash_utils.c	Sat Apr  3 19:38:44 2004
@@ -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>
@@ -49,6 +48,8 @@
 #include <asm/tlb.h>
 #include <asm/cacheflush.h>
 #include <asm/cputable.h>
+#include <asm/abs_addr.h>
+
 /*
  * Note:  pte   --> Linux PTE
  *        HPTE  --> PowerPC Hashed Page Table Entry
@@ -108,11 +109,11 @@
 
 		if (systemcfg->platform == PLATFORM_PSERIES_LPAR)
 			ret = pSeries_lpar_hpte_insert(hpteg, va,
-				(unsigned long)__v2a(addr) >> PAGE_SHIFT,
+				virt_to_abs(addr) >> PAGE_SHIFT,
 				0, mode, 1, large);
 		else
 			ret = pSeries_hpte_insert(hpteg, va,
-				(unsigned long)__v2a(addr) >> PAGE_SHIFT,
+				virt_to_abs(addr) >> PAGE_SHIFT,
 				0, mode, 1, large);
 
 		if (ret == -1) {
@@ -155,7 +156,7 @@
 			ppc64_terminate_msg(0x20, "hpt space");
 			loop_forever();
 		}
-		htab_data.htab = (HPTE *)__a2v(table);
+		htab_data.htab = abs_to_virt(table);
 
 		/* htab absolute addr + encoded htabsize */
 		_SDR1 = table + __ilog2(pteg_count) - 11;
diff -Nru a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c
--- a/arch/ppc64/mm/hugetlbpage.c	Sat Apr  3 19:38:43 2004
+++ b/arch/ppc64/mm/hugetlbpage.c	Sat Apr  3 19:38:43 2004
@@ -190,6 +190,9 @@
 	BUG_ON(!in_hugepage_area(mm->context, addr));
 
 	pgd = pgd_offset(mm, addr);
+	if (pgd_none(*pgd))
+		return NULL;
+
 	pmd = pmd_offset(pgd, addr);
 
 	/* We shouldn't find a (normal) PTE page pointer here */
@@ -250,8 +253,11 @@
 	/* Check no VMAs are in the region */
 	vma = find_vma(mm, TASK_HPAGE_BASE_32);
 
-	if (vma && (vma->vm_start < TASK_HPAGE_END_32))
+	if (vma && (vma->vm_start < TASK_HPAGE_END_32)) {
+		printk(KERN_DEBUG "Low HTLB region busy: PID=%d  vma @ %lx-%lx\n",
+		       current->pid, vma->vm_start, vma->vm_end);
 		return -EBUSY;
+	}
 
 	/* Clean up any leftover PTE pages in the region */
 	spin_lock(&mm->page_table_lock);
@@ -292,6 +298,16 @@
 	return 0;
 }
 
+int prepare_hugepage_range(unsigned long addr, unsigned long len)
+{
+	if (is_hugepage_high_range(addr, len))
+		return 0;
+	else if (is_hugepage_low_range(addr, len))
+		return open_32bit_htlbpage_range(current->mm);
+
+	return -EINVAL;
+}
+
 int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
 			struct vm_area_struct *vma)
 {
@@ -911,6 +927,13 @@
 {
 	return (size + ~HPAGE_MASK)/HPAGE_SIZE <= htlbpage_free;
 }
+
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+	return htlbpage_total * (HPAGE_SIZE / PAGE_SIZE);
+}
+EXPORT_SYMBOL(hugetlb_total_pages);
 
 /*
  * We cannot handle pagefaults against hugetlb pages at all.  They cause
diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c	Sat Apr  3 19:38:44 2004
+++ b/arch/ppc64/mm/init.c	Sat Apr  3 19:38:44 2004
@@ -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>
@@ -61,6 +60,7 @@
 #include <asm/sections.h>
 #include <asm/system.h>
 #include <asm/iommu.h>
+#include <asm/abs_addr.h>
 
 
 struct mmu_context_queue_t mmu_context_queue;
@@ -76,8 +76,6 @@
 
 unsigned long klimit = (unsigned long)_end;
 
-HPTE *Hash=0;
-unsigned long Hash_size=0;
 unsigned long _SDR1=0;
 unsigned long _ASR=0;
 
@@ -156,7 +154,7 @@
 		pmdp = pmd_alloc(&ioremap_mm, pgdp, ea);
 		ptep = pte_alloc_kernel(&ioremap_mm, pmdp, ea);
 
-		pa = absolute_to_phys(pa);
+		pa = abs_to_phys(pa);
 		set_pte(ptep, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
 		spin_unlock(&ioremap_mm.page_table_lock);
 	} else {
@@ -542,7 +540,7 @@
 	 */
 	bootmap_pages = bootmem_bootmap_pages(total_pages);
 
-	start = (unsigned long)__a2p(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));
+	start = abs_to_phys(lmb_alloc(bootmap_pages<<PAGE_SHIFT, PAGE_SIZE));
 	BUG_ON(!start);
 
 	boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
--- a/arch/ppc64/mm/numa.c	Sat Apr  3 19:38:45 2004
+++ b/arch/ppc64/mm/numa.c	Sat Apr  3 19:38:45 2004
@@ -15,6 +15,7 @@
 #include <linux/mmzone.h>
 #include <linux/module.h>
 #include <asm/lmb.h>
+#include <asm/machdep.h>
 
 #if 1
 #define dbg(args...) udbg_printf(args)
@@ -22,9 +23,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};
 
@@ -56,6 +65,11 @@
 	int *memory_associativity;
 	int depth;
 	int max_domain = 0;
+
+	if (strstr(saved_command_line, "numa=off")) {
+		printk(KERN_WARNING "NUMA disabled by user\n");
+		return -1;
+	}
 
 	cpu = of_find_node_by_type(NULL, "cpu");
 	if (!cpu)
diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c
--- a/arch/ppc64/xmon/xmon.c	Sat Apr  3 19:38:55 2004
+++ b/arch/ppc64/xmon/xmon.c	Sat Apr  3 19:38:55 2004
@@ -56,9 +56,6 @@
 #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 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 *);
@@ -177,7 +173,8 @@
   S	print special registers\n\
   t	print backtrace\n\
   T	Enable/Disable PPCDBG flags\n\
-  x	exit monitor\n\
+  x	exit monitor and recover\n\
+  X	exit monitor and dont recover\n\
   u	dump segment table or SLB\n\
   ?	help\n"
   "\
@@ -344,6 +341,9 @@
 #endif /* CONFIG_SMP */
 	set_msrd(msr);		/* restore interrupt enable */
 
+	if (cmd == 'X')
+		return 0;
+
 	return 1;
 }
 
@@ -563,6 +563,7 @@
 			break;
 		case 's':
 		case 'x':
+		case 'X':
 		case EOF:
 			return cmd;
 		case '?':
@@ -897,93 +898,75 @@
 	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 -Nru a/arch/s390/Kconfig b/arch/s390/Kconfig
--- a/arch/s390/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/s390/Kconfig	Sat Apr  3 19:38:43 2004
@@ -89,30 +89,16 @@
 	  singleprocessor machines. On a singleprocessor machine, the kernel
 	  will run faster if you say N here.
 
-	  See also the <file:Documentation/smp.tex>,
-	  <file:Documentation/smp.txt> and the SMP-HOWTO available at
-	  <http://www.tldp.org/docs.html#howto>.
+	  See also the <file:Documentation/smp.txt> and the SMP-HOWTO
+	  available at <http://www.tldp.org/docs.html#howto>.
 
 	  Even if you don't know what to do here, say Y.
 
 config NR_CPUS
-	int "Maximum number of CPUs (2-32)"
-	range 2 32
-	depends on SMP && ARCH_S390X = 'n'
-	default "32"
-	help
-	  This allows you to specify the maximum number of CPUs which this
-	  kernel will support.  The maximum supported value is 32 and the
-	  minimum value which makes sense is 2.
-
-	  This is purely to save memory - each supported CPU adds
-	  approximately eight kilobytes to the kernel image.
-	
-config NR_CPUS
 	int "Maximum number of CPUs (2-64)"
 	range 2 64
-	depends on SMP && ARCH_S390X
-	default "64"
+	depends on SMP
+	default "32"
 	help
 	  This allows you to specify the maximum number of CPUs which this
 	  kernel will support.  The maximum supported value is 64 and the
@@ -141,6 +127,11 @@
 config COMPAT
 	bool
 	depends on S390_SUPPORT
+	default y
+
+config SYSVIPC_COMPAT
+	bool
+	depends on COMPAT && SYSVIPC
 	default y
 
 config BINFMT_ELF32
diff -Nru a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
--- a/arch/s390/appldata/appldata_base.c	Sat Apr  3 19:38:42 2004
+++ b/arch/s390/appldata/appldata_base.c	Sat Apr  3 19:38:42 2004
@@ -233,8 +233,8 @@
 				.buffer_addr = virt_to_phys((void *) buffer)
 	};
 
-        if (!MACHINE_IS_VM)
-                return -ENOSYS;
+	if (!MACHINE_IS_VM)
+		return -ENOSYS;
 	ry = -1;
 	asm volatile(
 			"diag %1,%0,0xDC\n\t"
@@ -336,9 +336,9 @@
 		P_ERROR("Timer CPU interval has to be > 0!\n");
 		return -EINVAL;
 	}
-	per_cpu_interval = (u64) (interval*1000 / num_online_cpus()) * TOD_MICRO;
 
 	spin_lock(&appldata_timer_lock);
+	per_cpu_interval = (u64) (interval*1000 / num_online_cpus()) * TOD_MICRO;
 	appldata_interval = interval;
 	if (appldata_timer_active) {
 		for (i = 0; i < num_online_cpus(); i++) {
@@ -372,29 +372,59 @@
 appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
 			   void *buffer, size_t *lenp)
 {
-	struct appldata_ops *ops;
-	int rc, len;
+	struct appldata_ops *ops = NULL, *tmp_ops;
+	int rc, len, found;
 	char buf[2];
+	struct list_head *lh;
 
+	found = 0;
+	spin_lock_bh(&appldata_ops_lock);
+	list_for_each(lh, &appldata_ops_list) {
+		tmp_ops = list_entry(lh, struct appldata_ops, list);
+		if (&tmp_ops->ctl_table[2] == ctl) {
+			found = 1;
+		}
+	}
+	if (!found) {
+		spin_unlock_bh(&appldata_ops_lock);
+		return -ENODEV;
+	}
 	ops = ctl->data;
+	if (!try_module_get(ops->owner)) {	// protect this function
+		spin_unlock_bh(&appldata_ops_lock);
+		return -ENODEV;
+	}
+	spin_unlock_bh(&appldata_ops_lock);
+
 	if (!*lenp || filp->f_pos) {
 		*lenp = 0;
+		module_put(ops->owner);
 		return 0;
 	}
 	if (!write) {
 		len = sprintf(buf, ops->active ? "1\n" : "0\n");
 		if (len > *lenp)
 			len = *lenp;
-		if (copy_to_user(buffer, buf, len))
+		if (copy_to_user(buffer, buf, len)) {
+			module_put(ops->owner);
 			return -EFAULT;
+		}
 		goto out;
 	}
 	len = *lenp;
-	if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len))
+	if (copy_from_user(buf, buffer,
+			   len > sizeof(buf) ? sizeof(buf) : len)) {
+		module_put(ops->owner);
 		return -EFAULT;
+	}
 
 	spin_lock_bh(&appldata_ops_lock);
 	if ((buf[0] == '1') && (ops->active == 0)) {
+		if (!try_module_get(ops->owner)) {	// protect tasklet
+			spin_unlock_bh(&appldata_ops_lock);
+			module_put(ops->owner);
+			return -ENODEV;
+		}
 		ops->active = 1;
 		ops->callback(ops->data);	// init record
 		rc = appldata_diag(ops->record_nr,
@@ -403,6 +433,7 @@
 		if (rc != 0) {
 			P_ERROR("START DIAG 0xDC for %s failed, "
 				"return code: %d\n", ops->name, rc);
+			module_put(ops->owner);
 			ops->active = 0;
 		} else {
 			P_INFO("Monitoring %s data enabled, "
@@ -419,11 +450,13 @@
 			P_INFO("Monitoring %s data disabled, "
 				"DIAG 0xDC stopped.\n", ops->name);
 		}
+		module_put(ops->owner);
 	}
 	spin_unlock_bh(&appldata_ops_lock);
 out:
 	*lenp = len;
 	filp->f_pos += len;
+	module_put(ops->owner);
 	return 0;
 }
 
@@ -440,30 +473,26 @@
 {
 	struct list_head *lh;
 	struct appldata_ops *tmp_ops;
-	int rc, i;
+	int i;
 
-	rc = 0;
 	i = 0;
 
 	if ((ops->size > APPLDATA_MAX_REC_SIZE) ||
 		(ops->size < 0)){
 		P_ERROR("Invalid size of %s record = %i, maximum = %i!\n",
 			ops->name, ops->size, APPLDATA_MAX_REC_SIZE);
-		rc = -ENOMEM;
-		goto out;
+		return -ENOMEM;
 	}
 	if ((ops->ctl_nr == CTL_APPLDATA) ||
 	    (ops->ctl_nr == CTL_APPLDATA_TIMER) ||
 	    (ops->ctl_nr == CTL_APPLDATA_INTERVAL)) {
 		P_ERROR("ctl_nr %i already in use!\n", ops->ctl_nr);
-		rc = -EBUSY;
-		goto out;
+		return -EBUSY;
 	}
 	ops->ctl_table = kmalloc(4*sizeof(struct ctl_table), GFP_KERNEL);
 	if (ops->ctl_table == NULL) {
 		P_ERROR("Not enough memory for %s ctl_table!\n", ops->name);
-		rc = -ENOMEM;
-		goto out;
+		return -ENOMEM;
 	}
 	memset(ops->ctl_table, 0, 4*sizeof(struct ctl_table));
 
@@ -477,18 +506,16 @@
 			ops->ctl_nr);
 		if (strncmp(tmp_ops->name, ops->name,
 				APPLDATA_PROC_NAME_LENGTH) == 0) {
-			spin_unlock_bh(&appldata_ops_lock);
 			P_ERROR("Name \"%s\" already registered!\n", ops->name);
 			kfree(ops->ctl_table);
-			rc = -EBUSY;
-			goto out;
+			spin_unlock_bh(&appldata_ops_lock);
+			return -EBUSY;
 		}
 		if (tmp_ops->ctl_nr == ops->ctl_nr) {
-			spin_unlock_bh(&appldata_ops_lock);
 			P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
 			kfree(ops->ctl_table);
-			rc = -EBUSY;
-			goto out;
+			spin_unlock_bh(&appldata_ops_lock);
+			return -EBUSY;
 		}
 	}
 	list_add(&ops->list, &appldata_ops_list);
@@ -511,10 +538,9 @@
 	ops->ctl_table[3].ctl_name = 0;
 
 	ops->sysctl_header = register_sysctl_table(ops->ctl_table,1);
-	ops->ctl_table[2].de->owner = ops->owner;
+
 	P_INFO("%s-ops registered!\n", ops->name);
-out:
-	return rc;
+	return 0;
 }
 
 /*
@@ -524,25 +550,11 @@
  */
 void appldata_unregister_ops(struct appldata_ops *ops)
 {
-	int rc;
-
-	unregister_sysctl_table(ops->sysctl_header);
-	kfree(ops->ctl_table);
-	if (ops->active == 1) {
-		ops->active = 0;
-		rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
-				(unsigned long) ops->data, ops->size);
-		if (rc != 0) {
-			P_ERROR("STOP DIAG 0xDC for %s failed, "
-				"return code: %d\n", ops->name, rc);
-		} else {
-			P_INFO("Monitoring %s data disabled, "
-				"DIAG 0xDC stopped.\n", ops->name);
-		}
-
-	}
 	spin_lock_bh(&appldata_ops_lock);
+	unregister_sysctl_table(ops->sysctl_header);
 	list_del(&ops->list);
+	kfree(ops->ctl_table);
+	ops->ctl_table = NULL;
 	spin_unlock_bh(&appldata_ops_lock);
 	P_INFO("%s-ops unregistered!\n", ops->name);
 }
diff -Nru a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
--- a/arch/s390/appldata/appldata_mem.c	Sat Apr  3 19:38:41 2004
+++ b/arch/s390/appldata/appldata_mem.c	Sat Apr  3 19:38:41 2004
@@ -27,6 +27,15 @@
 
 /*
  * Memory data
+ *
+ * This is accessed as binary data by z/VM. If changes to it can't be avoided,
+ * the structure version (product ID, see appldata_base.c) needs to be changed
+ * as well and all documentation and z/VM applications using it must be
+ * updated.
+ *
+ * The record layout is documented in the Linux for zSeries Device Drivers
+ * book:
+ * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
 struct appldata_mem_data {
 	u64 timestamp;
@@ -105,11 +114,10 @@
 	mem_data->pgpgout    = ps.pgpgout >> 1;
 	mem_data->pswpin     = ps.pswpin;
 	mem_data->pswpout    = ps.pswpout;
-	mem_data->pgalloc    = ps.pgalloc;
+	mem_data->pgalloc    = ps.pgalloc_high + ps.pgalloc_normal +
+			       ps.pgalloc_dma;
 	mem_data->pgfault    = ps.pgfault;
 	mem_data->pgmajfault = ps.pgmajfault;
-
-P_DEBUG("pgalloc = %lu, pgfree = %lu\n", ps.pgalloc, ps.pgfree);
 
 	si_meminfo(&val);
 	mem_data->sharedram = val.sharedram;
diff -Nru a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
--- a/arch/s390/appldata/appldata_net_sum.c	Sat Apr  3 19:38:42 2004
+++ b/arch/s390/appldata/appldata_net_sum.c	Sat Apr  3 19:38:42 2004
@@ -26,6 +26,14 @@
 
 /*
  * Network data
+ *
+ * This is accessed as binary data by z/VM. If changes to it can't be avoided,
+ * the structure version (product ID, see appldata_base.c) needs to be changed
+ * as well and all documentation and z/VM applications using it must be updated.
+ *
+ * The record layout is documented in the Linux for zSeries Device Drivers
+ * book:
+ * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
 struct appldata_net_sum_data {
 	u64 timestamp;
diff -Nru a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
--- a/arch/s390/appldata/appldata_os.c	Sat Apr  3 19:38:57 2004
+++ b/arch/s390/appldata/appldata_os.c	Sat Apr  3 19:38:57 2004
@@ -28,6 +28,15 @@
 
 /*
  * OS data
+ *
+ * This is accessed as binary data by z/VM. If changes to it can't be avoided,
+ * the structure version (product ID, see appldata_base.c) needs to be changed
+ * as well and all documentation and z/VM applications using it must be
+ * updated.
+ *
+ * The record layout is documented in the Linux for zSeries Device Drivers
+ * book:
+ * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
 struct appldata_os_per_cpu {
 	u32 per_cpu_user;	/* timer ticks spent in user mode   */
diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig
--- a/arch/s390/defconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/s390/defconfig	Sat Apr  3 19:38:55 2004
@@ -21,9 +21,11 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_IKCONFIG is not set
+CONFIG_HOTPLUG=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
 # CONFIG_EMBEDDED is not set
-# CONFIG_KALLSYMS is not set
+CONFIG_KALLSYMS=y
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_IOSCHED_NOOP=y
@@ -84,6 +86,7 @@
 # Generic Driver Options
 #
 # CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # SCSI device support
@@ -110,6 +113,12 @@
 CONFIG_SCSI_LOGGING=y
 
 #
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
 # SCSI low-level drivers
 #
 # CONFIG_SCSI_AIC7XXX_OLD is not set
@@ -185,7 +194,6 @@
 # S/390 tape hardware support
 #
 CONFIG_S390_TAPE_34XX=m
-CONFIG_HOTPLUG=y
 
 #
 # Networking support
@@ -199,7 +207,7 @@
 # CONFIG_PACKET_MMAP is not set
 # CONFIG_NETLINK_DEV is not set
 CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
+CONFIG_NET_KEY=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -208,7 +216,6 @@
 # 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
@@ -222,11 +229,12 @@
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_NETFILTER is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER 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
@@ -247,6 +255,7 @@
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_CBQ=m
 # CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
 CONFIG_NET_SCH_CSZ=m
 CONFIG_NET_SCH_PRIO=m
 CONFIG_NET_SCH_RED=m
@@ -255,6 +264,7 @@
 CONFIG_NET_SCH_TBF=m
 CONFIG_NET_SCH_GRED=m
 CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_DELAY is not set
 CONFIG_NET_QOS=y
 CONFIG_NET_ESTIMATOR=y
 CONFIG_NET_CLS=y
@@ -303,6 +313,7 @@
 #
 # CONFIG_TR is not set
 # CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
 
 #
 # Wan interfaces
@@ -340,6 +351,8 @@
 # Bluetooth support
 #
 # CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
 
 #
 # File systems
@@ -380,7 +393,6 @@
 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
@@ -392,6 +404,7 @@
 # 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
@@ -417,7 +430,7 @@
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_CIFS is not set
 # CONFIG_NCP_FS is not set
@@ -484,7 +497,9 @@
 # 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_MICHAEL_MIC is not set
 # CONFIG_CRYPTO_TEST is not set
 
 #
diff -Nru a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
--- a/arch/s390/kernel/asm-offsets.c	Sat Apr  3 19:38:42 2004
+++ b/arch/s390/kernel/asm-offsets.c	Sat Apr  3 19:38:42 2004
@@ -17,15 +17,26 @@
 int main(void)
 {
 	DEFINE(__THREAD_info, offsetof(struct task_struct, thread_info),);
-	DEFINE(__THREAD_ar2, offsetof(struct task_struct, thread.ar2),);
-	DEFINE(__THREAD_ar4, offsetof(struct task_struct, thread.ar4),);
 	DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
 	DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
+	DEFINE(__THREAD_mm_segment,
+	       offsetof(struct task_struct, thread.mm_segment),);
+	BLANK();
+	DEFINE(__PER_atmid, offsetof(per_struct, lowcore.words.perc_atmid),);
+	DEFINE(__PER_address, offsetof(per_struct, lowcore.words.address),);
+	DEFINE(__PER_access_id, offsetof(per_struct, lowcore.words.access_id),);
 	BLANK();
 	DEFINE(__TI_task, offsetof(struct thread_info, task),);
 	DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain),);
 	DEFINE(__TI_flags, offsetof(struct thread_info, flags),);
 	DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
 	DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
+	BLANK();
+	DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),);
+	DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),);
+	DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),);
+	DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc),);
+	DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap),);
+	DEFINE(__PT_SIZE, sizeof(struct pt_regs),);
 	return 0;
 }
diff -Nru a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c
--- a/arch/s390/kernel/binfmt_elf32.c	Sat Apr  3 19:38:55 2004
+++ b/arch/s390/kernel/binfmt_elf32.c	Sat Apr  3 19:38:55 2004
@@ -57,18 +57,7 @@
 /* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
    now struct_user_regs, they are different) */
 
-#define ELF_CORE_COPY_REGS(pr_reg, regs)        \
-	{ \
-	int i; \
-	memcpy(&pr_reg.psw.mask, &regs->psw.mask, 4); \
-	memcpy(&pr_reg.psw.addr, ((char*)&regs->psw.addr)+4, 4); \
-	for(i=0; i<NUM_GPRS; i++) \
-		pr_reg.gprs[i] = regs->gprs[i]; \
-	for(i=0; i<NUM_ACRS; i++) \
-		pr_reg.acrs[i] = regs->acrs[i]; \
-	pr_reg.orig_gpr2 = regs->orig_gpr2; \
-	}
-
+#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs32(regs, &pr_reg);
 
 
 /* This yields a mask that user programs can use to figure out what
@@ -106,6 +95,18 @@
 	__u32		orig_gpr2;
 } s390_regs32;
 typedef s390_regs32 elf_gregset_t;
+
+static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs)
+{
+	int i;
+
+	memcpy(&regs->psw.mask, &ptregs->psw.mask, 4);
+	memcpy(&regs->psw.addr, &ptregs->psw.addr, 4);
+	for (i = 0; i < NUM_GPRS; i++)
+		regs->gprs[i] = ptregs->gprs[i];
+	regs->orig_gpr2 = ptregs->orig_gpr2;
+	return 1;
+}
 
 #include <asm/processor.h>
 #include <linux/module.h>
diff -Nru a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
--- a/arch/s390/kernel/compat_linux.c	Sat Apr  3 19:38:55 2004
+++ b/arch/s390/kernel/compat_linux.c	Sat Apr  3 19:38:55 2004
@@ -35,9 +35,6 @@
 #include <linux/slab.h>
 #include <linux/uio.h>
 #include <linux/nfs_fs.h>
-#include <linux/smb_fs.h>
-#include <linux/smb_mount.h>
-#include <linux/ncp_fs.h>
 #include <linux/quota.h>
 #include <linux/module.h>
 #include <linux/sunrpc/svc.h>
@@ -293,629 +290,74 @@
 		 __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.
  *
  * This is really horribly ugly.
  */
-asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr)
+asmlinkage long 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)
+asmlinkage long sys32_truncate64(const char * path, unsigned long high, unsigned long low)
 {
 	if ((int)high < 0)
 		return -EINVAL;
@@ -923,7 +365,7 @@
 		return sys_truncate(path, (high << 32) | low);
 }
 
-asmlinkage int sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
+asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
 {
 	if ((int)high < 0)
 		return -EINVAL;
@@ -1034,7 +476,7 @@
 	return retval;
 }
 
-asmlinkage long sys32_readv(int fd, struct compat_iovec *vector, u32 count)
+asmlinkage long sys32_readv(int fd, struct compat_iovec *vector, unsigned long count)
 {
 	struct file *file;
 	long ret = -EBADF;
@@ -1052,7 +494,7 @@
 	return ret;
 }
 
-asmlinkage long sys32_writev(int fd, struct compat_iovec *vector, u32 count)
+asmlinkage long sys32_writev(int fd, struct compat_iovec *vector, unsigned long count)
 {
 	struct file *file;
 	int ret = -EBADF;
@@ -1104,7 +546,7 @@
 	return 0;
 }
 
-asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count)
+asmlinkage long old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count)
 {
 	int error = -EBADF;
 	struct file * file;
@@ -1166,7 +608,7 @@
 	return 0;
 }
 
-asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count)
+asmlinkage long sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count)
 {
 	struct file * file;
 	struct linux_dirent32 * lastdirent;
@@ -1261,10 +703,10 @@
 #define MAX_SELECT_SECONDS \
 	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
 
-asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
+asmlinkage long sys32_select(int n, u32 *inp, u32 *outp, u32 *exp,
+				struct compat_timeval *tvp)
 {
 	fd_set_bits fds;
-	struct compat_timeval *tvp = (struct compat_timeval *)AA(tvp_x);
 	char *bits;
 	unsigned long nn;
 	long timeout;
@@ -1383,162 +825,6 @@
 	return err;
 }
 
-asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2)
-{
-	return sys_sysfs(option, arg1, arg2);
-}
-
-struct ncp_mount_data32 {
-        int version;
-        unsigned int ncp_fd;
-        compat_uid_t mounted_uid;
-        compat_pid_t wdog_pid;
-        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
-        unsigned int time_out;
-        unsigned int retry_count;
-        unsigned int flags;
-        compat_uid_t uid;
-        compat_gid_t gid;
-        compat_mode_t file_mode;
-        compat_mode_t dir_mode;
-};
-
-static void *do_ncp_super_data_conv(void *raw_data)
-{
-	struct ncp_mount_data *n = (struct ncp_mount_data *)raw_data;
-	struct ncp_mount_data32 *n32 = (struct ncp_mount_data32 *)raw_data;
-
-	n->dir_mode = n32->dir_mode;
-	n->file_mode = n32->file_mode;
-	n->gid = low2highgid(n32->gid);
-	n->uid = low2highuid(n32->uid);
-	memmove (n->mounted_vol, n32->mounted_vol, (sizeof (n32->mounted_vol) + 3 * sizeof (unsigned int)));
-	n->wdog_pid = n32->wdog_pid;
-	n->mounted_uid = low2highuid(n32->mounted_uid);
-	return raw_data;
-}
-
-struct smb_mount_data32 {
-        int version;
-        compat_uid_t mounted_uid;
-        compat_uid_t uid;
-        compat_gid_t gid;
-        compat_mode_t file_mode;
-        compat_mode_t dir_mode;
-};
-
-static void *do_smb_super_data_conv(void *raw_data)
-{
-	struct smb_mount_data *s = (struct smb_mount_data *)raw_data;
-	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
-
-	if (s32->version != SMB_MOUNT_OLDVERSION)
-		goto out;
-	s->version = s32->version;
-	s->mounted_uid = low2highuid(s32->mounted_uid);
-	s->uid = low2highuid(s32->uid);
-	s->gid = low2highgid(s32->gid);
-	s->file_mode = s32->file_mode;
-	s->dir_mode = s32->dir_mode;
-out:
-	return raw_data;
-}
-
-static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
-{
-	int i;
-	unsigned long page;
-	struct vm_area_struct *vma;
-
-	*kernel = 0;
-	if(!user)
-		return 0;
-	vma = find_vma(current->mm, (unsigned long)user);
-	if(!vma || (unsigned long)user < vma->vm_start)
-		return -EFAULT;
-	if(!(vma->vm_flags & VM_READ))
-		return -EFAULT;
-	i = vma->vm_end - (unsigned long) user;
-	if(PAGE_SIZE <= (unsigned long) i)
-		i = PAGE_SIZE - 1;
-	if(!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
-	if(copy_from_user((void *) page, user, i)) {
-		free_page(page);
-		return -EFAULT;
-	}
-	*kernel = page;
-	return 0;
-}
-
-#define SMBFS_NAME	"smbfs"
-#define NCPFS_NAME	"ncpfs"
-
-asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
-{
-	unsigned long type_page = 0;
-	unsigned long data_page = 0;
-	unsigned long dev_page = 0;
-	unsigned long dir_page = 0;
-	int err, is_smb, is_ncp;
-
-	is_smb = is_ncp = 0;
-
-	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
-	if (err)
-		goto out;
-
-	if (!type_page) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	is_smb = !strcmp((char *)type_page, SMBFS_NAME);
-	is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
-
-	err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
-	if (err)
-		goto type_out;
-
-	err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
-	if (err)
-		goto data_out;
-
-	err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
-	if (err)
-		goto dev_out;
-
-	if (!is_smb && !is_ncp) {
-		lock_kernel();
-		err = do_mount((char*)dev_page, (char*)dir_page,
-				(char*)type_page, new_flags, (char*)data_page);
-		unlock_kernel();
-	} else {
-		if (is_ncp)
-			do_ncp_super_data_conv((void *)data_page);
-		else
-			do_smb_super_data_conv((void *)data_page);
-
-		lock_kernel();
-		err = do_mount((char*)dev_page, (char*)dir_page,
-				(char*)type_page, new_flags, (char*)data_page);
-		unlock_kernel();
-	}
-	free_page(dir_page);
-
-dev_out:
-	free_page(dev_page);
-
-data_out:
-	free_page(data_page);
-
-type_out:
-	free_page(type_page);
-
-out:
-	return err;
-}
-
 struct sysinfo32 {
         s32 uptime;
         u32 loads[3];
@@ -1556,7 +842,7 @@
         char _f[8];
 };
 
-asmlinkage int sys32_sysinfo(struct sysinfo32 __user *info)
+asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
 {
 	struct sysinfo s;
 	int ret, err;
@@ -1584,7 +870,7 @@
 	return ret;
 }
 
-asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
+asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
 				struct compat_timespec __user *interval)
 {
 	struct timespec t;
@@ -1599,8 +885,8 @@
 	return ret;
 }
 
-asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
-			compat_sigset_t __user *oset, compat_size_t sigsetsize)
+asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
+			compat_sigset_t __user *oset, size_t sigsetsize)
 {
 	sigset_t s;
 	compat_sigset_t s32;
@@ -1634,8 +920,8 @@
 	return 0;
 }
 
-asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *set,
-				compat_size_t sigsetsize)
+asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
+				size_t sigsetsize)
 {
 	sigset_t s;
 	compat_sigset_t s32;
@@ -1661,9 +947,9 @@
 extern int
 copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from);
 
-asmlinkage int
+asmlinkage long
 sys32_rt_sigtimedwait(compat_sigset_t *uthese, siginfo_t32 *uinfo,
-		      struct compat_timespec *uts, compat_size_t sigsetsize)
+		      struct compat_timespec *uts, size_t sigsetsize)
 {
 	int ret, sig;
 	sigset_t these;
@@ -1742,7 +1028,7 @@
 	return ret;
 }
 
-asmlinkage int
+asmlinkage long
 sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 __user *uinfo)
 {
 	siginfo_t info;
@@ -1944,7 +1230,7 @@
  * sys32_execve() executes a new program after the asm stub has set
  * things up for us.  This should basically do what I want it to.
  */
-asmlinkage int
+asmlinkage long
 sys32_execve(struct pt_regs regs)
 {
         int error;
@@ -1972,14 +1258,14 @@
 
 #ifdef CONFIG_MODULES
 
-asmlinkage int
+asmlinkage long
 sys32_init_module(void __user *umod, unsigned long len,
 		const char __user *uargs)
 {
 	return sys_init_module(umod, len, uargs);
 }
 
-asmlinkage int
+asmlinkage long
 sys32_delete_module(const char __user *name_user, unsigned int flags)
 {
 	return sys_delete_module(name_user, flags);
@@ -1987,14 +1273,14 @@
 
 #else /* CONFIG_MODULES */
 
-asmlinkage int
+asmlinkage long
 sys32_init_module(void __user *umod, unsigned long len,
 		const char __user *uargs)
 {
 	return -ENOSYS;
 }
 
-asmlinkage int
+asmlinkage long
 sys32_delete_module(const char __user *name_user, unsigned int flags)
 {
 	return -ENOSYS;
@@ -2159,7 +1445,7 @@
 	return copy_to_user(res32, kres, sizeof(*res32)) ? -EFAULT : 0;
 }
 
-int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
+long asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
 {
 	struct nfsctl_arg *karg = NULL;
 	union nfsctl_res *kres = NULL;
@@ -2227,7 +1513,7 @@
 
 extern struct timezone sys_tz;
 
-asmlinkage int sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
+asmlinkage long sys32_gettimeofday(struct compat_timeval *tv, struct timezone *tz)
 {
 	if (tv) {
 		struct timeval ktv;
@@ -2256,7 +1542,7 @@
 	return 0;
 }
 
-asmlinkage int sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
+asmlinkage long sys32_settimeofday(struct compat_timeval *tv, struct timezone *tz)
 {
 	struct timespec kts;
 	struct timezone ktz;
@@ -2273,62 +1559,24 @@
 	return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
-asmlinkage int sys32_utimes(char __user *filename,
-			struct compat_timeval __user *tvs)
-{
-	char *kfilename;
-	struct timeval ktvs[2];
-	mm_segment_t old_fs;
-	int ret;
-
-	kfilename = getname(filename);
-	ret = PTR_ERR(kfilename);
-	if (!IS_ERR(kfilename)) {
-		if (tvs) {
-			if (get_tv32(&ktvs[0], tvs) ||
-			    get_tv32(&ktvs[1], 1+tvs))
-				return -EFAULT;
-		}
-
-		old_fs = get_fs();
-		set_fs(KERNEL_DS);
-		ret = sys_utimes(kfilename, &ktvs[0]);
-		set_fs(old_fs);
-
-		putname(kfilename);
-	}
-	return ret;
-}
-
 /* These are here just in case some old sparc32 binary calls it. */
-asmlinkage int sys32_pause(void)
+asmlinkage long sys32_pause(void)
 {
 	current->state = TASK_INTERRUPTIBLE;
 	schedule();
 	return -ERESTARTNOHAND;
 }
 
-
-asmlinkage int sys32_prctl(int option, u32 arg2, u32 arg3, u32 arg4, u32 arg5)
-{
-	return sys_prctl(option,
-			 (unsigned long) arg2,
-			 (unsigned long) arg3,
-			 (unsigned long) arg4,
-			 (unsigned long) arg5);
-}
-
-
-asmlinkage compat_ssize_t sys32_pread64(unsigned int fd, char *ubuf,
-				 compat_size_t count, u32 poshi, u32 poslo)
+asmlinkage long sys32_pread64(unsigned int fd, char *ubuf,
+				size_t count, u32 poshi, u32 poslo)
 {
 	if ((compat_ssize_t) count < 0)
 		return -EINVAL;
 	return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
-asmlinkage compat_ssize_t sys32_pwrite64(unsigned int fd, char *ubuf,
-				  compat_size_t count, u32 poshi, u32 poslo)
+asmlinkage long sys32_pwrite64(unsigned int fd, const char *ubuf,
+				size_t count, u32 poshi, u32 poslo)
 {
 	if ((compat_ssize_t) count < 0)
 		return -EINVAL;
@@ -2340,7 +1588,7 @@
 	return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
 }
 
-asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
+asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, size_t count)
 {
 	mm_segment_t old_fs = get_fs();
 	int ret;
@@ -2359,7 +1607,7 @@
 	return ret;
 }
 
-asmlinkage int sys32_sendfile64(int out_fd, int in_fd, 
+asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
 				compat_loff_t *offset, s32 count)
 {
 	mm_segment_t old_fs = get_fs();
@@ -2396,7 +1644,7 @@
 
 extern int do_adjtimex(struct timex *);
 
-asmlinkage int sys32_adjtimex(struct timex32 *utp)
+asmlinkage long sys32_adjtimex(struct timex32 *utp)
 {
 	struct timex txc;
 	int ret;
@@ -2452,13 +1700,6 @@
 	return ret;
 }
 
-asmlinkage int sys_setpriority32(u32 which, u32 who, u32 niceval)
-{
-	return sys_setpriority((int) which,
-			       (int) who,
-			       (int) niceval);
-}
-
 struct __sysctl_args32 {
 	u32 name;
 	int nlen;
@@ -2556,7 +1797,7 @@
 	return copy_to_user(ubuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; 
 }
 
-asmlinkage long sys32_stat64(char * filename, struct stat64_emu31 * statbuf, long flags)
+asmlinkage long sys32_stat64(char * filename, struct stat64_emu31 * statbuf)
 {
 	struct kstat stat;
 	int ret = vfs_stat(filename, &stat);
@@ -2565,7 +1806,7 @@
 	return ret;
 }
 
-asmlinkage long sys32_lstat64(char * filename, struct stat64_emu31 * statbuf, long flags)
+asmlinkage long sys32_lstat64(char * filename, struct stat64_emu31 * statbuf)
 {
 	struct kstat stat;
 	int ret = vfs_lstat(filename, &stat);
@@ -2574,7 +1815,7 @@
 	return ret;
 }
 
-asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 * statbuf, long flags)
+asmlinkage long sys32_fstat64(unsigned long fd, struct stat64_emu31 * statbuf)
 {
 	struct kstat stat;
 	int ret = vfs_fstat(fd, &stat);
@@ -2661,7 +1902,7 @@
 	return error;
 }
 
-asmlinkage compat_ssize_t sys32_read(unsigned int fd, char * buf, size_t count)
+asmlinkage long sys32_read(unsigned int fd, char * buf, size_t count)
 {
 	if ((compat_ssize_t) count < 0)
 		return -EINVAL; 
@@ -2669,7 +1910,7 @@
 	return sys_read(fd, buf, count);
 }
 
-asmlinkage compat_ssize_t sys32_write(unsigned int fd, char * buf, size_t count)
+asmlinkage long sys32_write(unsigned int fd, char * buf, size_t count)
 {
 	if ((compat_ssize_t) count < 0)
 		return -EINVAL; 
@@ -2677,7 +1918,7 @@
 	return sys_write(fd, buf, count);
 }
 
-asmlinkage int sys32_clone(struct pt_regs regs)
+asmlinkage long sys32_clone(struct pt_regs regs)
 {
         unsigned long clone_flags;
         unsigned long newsp;
diff -Nru a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
--- a/arch/s390/kernel/compat_linux.h	Sat Apr  3 19:38:45 2004
+++ b/arch/s390/kernel/compat_linux.h	Sat Apr  3 19:38:45 2004
@@ -144,6 +144,11 @@
 			 PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
 			 PSW32_MASK_PSTATE)
 
+#define PSW32_MASK_MERGE(CURRENT,NEW) \
+        (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
+         ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
+
+
 typedef struct
 {
 	_psw_t32	psw;
diff -Nru a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
--- a/arch/s390/kernel/compat_signal.c	Sat Apr  3 19:38:55 2004
+++ b/arch/s390/kernel/compat_signal.c	Sat Apr  3 19:38:55 2004
@@ -53,8 +53,6 @@
 
 asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
 
-int do_signal32(struct pt_regs *regs, sigset_t *oldset);
-
 int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
 {
 	int err;
@@ -123,7 +121,7 @@
 	while (1) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
-		if (do_signal32(regs, &saveset))
+		if (do_signal(regs, &saveset))
 			return -EINTR;
 	}
 }
@@ -158,12 +156,12 @@
         while (1) {
                 set_current_state(TASK_INTERRUPTIBLE);
                 schedule();
-                if (do_signal32(regs, &saveset))
+                if (do_signal(regs, &saveset))
                         return -EINTR;
         }
 }                                                         
 
-asmlinkage int
+asmlinkage long
 sys32_sigaction(int sig, const struct old_sigaction32 *act,
 		 struct old_sigaction32 *oact)
 {
@@ -256,7 +254,7 @@
 	return ret;
 }
 
-asmlinkage int
+asmlinkage long
 sys32_sigaltstack(const stack_t32 *uss, stack_t32 *uoss, struct pt_regs *regs)
 {
 	stack_t kss, koss;
@@ -294,12 +292,13 @@
 	_s390_regs_common32 regs32;
 	int err, i;
 
-	regs32.psw.mask = PSW32_USER_BITS |
-		((__u32)(regs->psw.mask >> 32) & PSW32_MASK_CC);
+	regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS,
+					   (__u32)(regs->psw.mask >> 32));
 	regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
 	for (i = 0; i < NUM_GPRS; i++)
 		regs32.gprs[i] = (__u32) regs->gprs[i];
-	memcpy(regs32.acrs, regs->acrs, sizeof(regs32.acrs));
+	save_access_regs(current->thread.acrs);
+	memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs));
 	err = __copy_to_user(&sregs->regs, &regs32, sizeof(regs32));
 	if (err)
 		return err;
@@ -320,12 +319,13 @@
 	err = __copy_from_user(&regs32, &sregs->regs, sizeof(regs32));
 	if (err)
 		return err;
-	regs->psw.mask = PSW_USER32_BITS |
-		(__u64)(regs32.psw.mask & PSW32_MASK_CC) << 32;
+	regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,
+				        (__u64)regs32.psw.mask << 32);
 	regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
 	for (i = 0; i < NUM_GPRS; i++)
 		regs->gprs[i] = (__u64) regs32.gprs[i];
-	memcpy(regs->acrs, regs32.acrs, sizeof(regs32.acrs));
+	memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs));
+	restore_access_regs(current->thread.acrs);
 
 	err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
 			       sizeof(_s390_fp_regs32));
@@ -482,7 +482,6 @@
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (__u64) frame;
 	regs->psw.addr = (__u64) ka->sa.sa_handler;
-	regs->psw.mask = PSW_USER32_BITS;
 
 	regs->gprs[2] = map_signal(sig);
 	regs->gprs[3] = (__u64) &frame->sc;
@@ -539,7 +538,6 @@
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (__u64) frame;
 	regs->psw.addr = (__u64) ka->sa.sa_handler;
-	regs->psw.mask = PSW_USER32_BITS;
 
 	regs->gprs[2] = map_signal(sig);
 	regs->gprs[3] = (__u64) &frame->info;
@@ -556,36 +554,12 @@
  * OK, we're invoking a handler
  */	
 
-static void
+void
 handle_signal32(unsigned long sig, siginfo_t *info, sigset_t *oldset,
 	struct pt_regs * regs)
 {
 	struct k_sigaction *ka = &current->sighand->action[sig-1];
 
-	/* Are we from a system call? */
-	if (regs->trap == __LC_SVC_OLD_PSW) {
-		/* If so, check system call restarting.. */
-		switch (regs->gprs[2]) {
-			case -ERESTART_RESTARTBLOCK:
-				current_thread_info()->restart_block.fn =
-					do_no_restart_syscall;
-				clear_thread_flag(TIF_RESTART_SVC);
-			case -ERESTARTNOHAND:
-				regs->gprs[2] = -EINTR;
-				break;
-
-			case -ERESTARTSYS:
-				if (!(ka->sa.sa_flags & SA_RESTART)) {
-					regs->gprs[2] = -EINTR;
-					break;
-				}
-			/* fallthrough */
-			case -ERESTARTNOINTR:
-				regs->gprs[2] = regs->orig_gpr2;
-				regs->psw.addr -= regs->ilc;
-		}
-	}
-
 	/* Set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		setup_rt_frame32(sig, ka, info, oldset, regs);
@@ -604,53 +578,3 @@
 	}
 }
 
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- *
- * Note that we go through the signals twice: once to check the signals that
- * the kernel can handle, and then we build all the user-level signal handling
- * stack-frames in one go after that.
- */
-int do_signal32(struct pt_regs *regs, sigset_t *oldset)
-{
-	siginfo_t info;
-	int signr;
-
-	/*
-	 * We want the common case to go fast, which
-	 * is why we may in certain cases get here from
-	 * kernel mode. Just return without doing anything
-	 * if so.
-	 */
-	if (!user_mode(regs))
-		return 1;
-
-	if (!oldset)
-		oldset = &current->blocked;
-
-	signr = get_signal_to_deliver(&info, regs, NULL);
-	if (signr > 0) {
-		/* Whee!  Actually deliver the signal.  */
-		handle_signal32(signr, &info, oldset, regs);
-		return 1;
-	}
-
-	/* Did we come from a system call? */
-	if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) {
-		/* Restart the system call - no handlers present */
-		if (regs->gprs[2] == -ERESTARTNOHAND ||
-		    regs->gprs[2] == -ERESTARTSYS ||
-		    regs->gprs[2] == -ERESTARTNOINTR) {
-			regs->gprs[2] = regs->orig_gpr2;
-			regs->psw.addr -= regs->ilc;
-		}
-		/* Restart the system call with a new system call number */
-		if (regs->gprs[2] == -ERESTART_RESTARTBLOCK) {
-			regs->gprs[2] = __NR_restart_syscall;
-			set_thread_flag(TIF_RESTART_SVC);
-		}
-	}
-	return 0;
-}
diff -Nru a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
--- a/arch/s390/kernel/compat_wrapper.S	Sat Apr  3 19:38:57 2004
+++ b/arch/s390/kernel/compat_wrapper.S	Sat Apr  3 19:38:57 2004
@@ -102,7 +102,7 @@
 	llgtr	%r4,%r4			# char *
 	llgfr	%r5,%r5			# unsigned long
 	llgtr	%r6,%r6			# void *
-	jg	sys32_mount		# branch to system call
+	jg	compat_sys_mount	# branch to system call
 
 	.globl  sys32_oldumount_wrapper 
 sys32_oldumount_wrapper:
@@ -126,7 +126,7 @@
 
 	.globl  sys32_alarm_wrapper 
 sys32_alarm_wrapper:
-	llgtr	%r2,%r2			# unsigned int
+	llgfr	%r2,%r2			# unsigned int
 	jg	sys_alarm		# branch to system call
 
 #sys32_pause_wrapper			# void 
@@ -203,7 +203,7 @@
 	.globl sys32_signal_wrapper
 sys32_signal_wrapper:
 	lgfr	%r2,%r2			# int 
-	llgfr	%r3,%r3			# __sighandler_t 
+	llgtr	%r3,%r3			# __sighandler_t
 	jg	sys_signal
 
 #sys32_geteuid16_wrapper		# void 
@@ -243,7 +243,7 @@
 
 	.globl  sys32_umask_wrapper 
 sys32_umask_wrapper:
-	lgfr	%r3,%r3			# int
+	lgfr	%r2,%r2			# int
 	jg	sys_umask		# branch to system call
 
 	.globl  sys32_chroot_wrapper 
@@ -273,6 +273,7 @@
 sys32_sigaction_wrapper:
 	lgfr	%r2,%r2			# int 
 	llgtr	%r3,%r3			# const struct old_sigaction *
+	llgtr	%r4,%r4			# struct old_sigaction32 *
 	jg	sys32_sigaction		# branch to system call
 
 	.globl  sys32_setreuid16_wrapper 
@@ -424,8 +425,8 @@
 	.globl  sys32_fchown16_wrapper 
 sys32_fchown16_wrapper:
 	llgfr	%r2,%r2			# unsigned int
-	llgtr	%r3,%r3			# __kernel_old_uid_emu31_t *
-	llgtr	%r4,%r4			# __kernel_old_gid_emu31_t *
+	llgfr	%r3,%r3			# compat_uid_t
+	llgfr	%r4,%r4			# compat_uid_t
 	jg	sys32_fchown16		# branch to system call
 
 	.globl  sys32_getpriority_wrapper 
@@ -523,7 +524,7 @@
 	lgfr	%r3,%r3			# int
 	lgfr	%r4,%r4			# int
 	lgfr	%r5,%r5			# int
-	llgtr	%r6,%r6			# void *
+	llgfr	%r6,%r6			# u32
 	jg	sys32_ipc		# branch to system call
 
 	.globl  sys32_fsync_wrapper 
@@ -580,9 +581,9 @@
 
 	.globl  sys32_quotactl_wrapper 
 sys32_quotactl_wrapper:
-	lgfr	%r2,%r2			# int
+	llgfr	%r2,%r2			# unsigned int
 	llgtr	%r3,%r3			# const char *
-	lgfr	%r4,%r4			# int
+	llgfr	%r4,%r4			# qid_t
 	llgtr	%r5,%r5			# caddr_t
 	jg	sys_quotactl		# branch to system call
 
@@ -664,14 +665,14 @@
 
 	.globl  sys32_readv_wrapper 
 sys32_readv_wrapper:
-	llgfr	%r2,%r2			# unsigned long
+	lgfr	%r2,%r2			# int
 	llgtr	%r3,%r3			# const struct iovec_emu31 *
 	llgfr	%r4,%r4			# unsigned long
 	jg	sys32_readv		# branch to system call
 
 	.globl  sys32_writev_wrapper 
 sys32_writev_wrapper:
-	llgfr	%r2,%r2			# unsigned long
+	lgfr	%r2,%r2			# int
 	llgtr	%r3,%r3			# const struct iovec_emu31 *
 	llgfr	%r4,%r4			# unsigned long
 	jg	sys32_writev		# branch to system call
@@ -830,6 +831,7 @@
 	lgfr	%r2,%r2			# int
 	llgtr	%r3,%r3			# old_sigset_emu31 *
 	llgtr	%r4,%r4			# old_sigset_emu31 *
+	llgfr	%r5,%r5			# size_t
 	jg	sys32_rt_sigprocmask	# branch to system call
 
 	.globl  sys32_rt_sigpending_wrapper 
@@ -917,15 +919,15 @@
 	.globl  sys32_truncate64_wrapper 
 sys32_truncate64_wrapper:
 	llgtr	%r2,%r2			# const char *
-	lgfr	%r3,%r3			# s32 
-	llgfr	%r4,%r4			# u32 
+	llgfr	%r3,%r3			# unsigned long
+	llgfr	%r4,%r4			# unsigned long
 	jg	sys32_truncate64	# branch to system call
 
 	.globl  sys32_ftruncate64_wrapper 
 sys32_ftruncate64_wrapper:
 	llgfr	%r2,%r2			# unsigned int
-	lgfr	%r3,%r3			# s32 
-	llgfr	%r4,%r4			# u32 
+	llgfr	%r3,%r3			# unsigned long
+	llgfr	%r4,%r4			# unsigned long
 	jg	sys32_ftruncate64	# branch to system call
 
 	.globl sys32_lchown_wrapper	
@@ -1064,14 +1066,12 @@
 sys32_stat64_wrapper:
 	llgtr	%r2,%r2			# char *
 	llgtr	%r3,%r3			# struct stat64 *
-	llgfr	%r4,%r4			# long
 	jg	sys32_stat64		# branch to system call
 
 	.globl	sys32_lstat64_wrapper
 sys32_lstat64_wrapper:
 	llgtr	%r2,%r2			# char *
 	llgtr	%r3,%r3			# struct stat64 *
-	llgfr	%r4,%r4			# long
 	jg	sys32_lstat64		# branch to system call
 
 	.globl	sys32_stime_wrapper
@@ -1088,7 +1088,6 @@
 sys32_fstat64_wrapper:
 	llgfr	%r2,%r2			# unsigned long
 	llgtr	%r3,%r3			# struct stat64 *
-	llgfr	%r4,%r4			# long
 	jg	sys32_fstat64		# branch to system call
 
 	.globl  compat_sys_futex_wrapper 
@@ -1097,6 +1096,7 @@
 	lgfr	%r3,%r3			# int
 	lgfr	%r4,%r4			# int
 	llgtr	%r5,%r5			# struct compat_timespec *
+	llgtr	%r6,%r6			# u32 *
 	jg	compat_sys_futex	# branch to system call
 
 	.globl	sys32_setxattr_wrapper
@@ -1338,3 +1338,17 @@
 	llgtr	%r3,%r3			# struct iocb *
 	llgtr	%r4,%r4			# struct io_event *
 	jg	sys_io_cancel
+
+	.globl compat_sys_statfs64_wrapper
+compat_sys_statfs64_wrapper:
+	llgtr	%r2,%r2			# const char *
+	llgfr	%r3,%r3			# compat_size_t
+	llgtr	%r4,%r4			# struct compat_statfs64 *
+	jg	compat_statfs64
+
+	.globl compat_sys_fstatfs64_wrapper
+compat_sys_fstatfs64_wrapper:
+	llgfr	%r2,%r2			# unsigned int fd
+	llgfr	%r3,%r3			# compat_size_t
+	llgtr	%r4,%r4			# struct compat_statfs64 *
+	jg	compat_fstatfs64
diff -Nru a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
--- a/arch/s390/kernel/entry.S	Sat Apr  3 19:38:41 2004
+++ b/arch/s390/kernel/entry.S	Sat Apr  3 19:38:41 2004
@@ -25,40 +25,32 @@
  * The first few entries are identical to the user_regs_struct.
  */
 SP_PTREGS    =  STACK_FRAME_OVERHEAD 
-SP_PSW       =  STACK_FRAME_OVERHEAD + PT_PSWMASK
-SP_R0        =  STACK_FRAME_OVERHEAD + PT_GPR0
-SP_R1        =  STACK_FRAME_OVERHEAD + PT_GPR1
-SP_R2        =  STACK_FRAME_OVERHEAD + PT_GPR2
-SP_R3        =  STACK_FRAME_OVERHEAD + PT_GPR3
-SP_R4        =  STACK_FRAME_OVERHEAD + PT_GPR4
-SP_R5        =  STACK_FRAME_OVERHEAD + PT_GPR5
-SP_R6        =  STACK_FRAME_OVERHEAD + PT_GPR6
-SP_R7        =  STACK_FRAME_OVERHEAD + PT_GPR7
-SP_R8        =  STACK_FRAME_OVERHEAD + PT_GPR8
-SP_R9        =  STACK_FRAME_OVERHEAD + PT_GPR9
-SP_R10       =  STACK_FRAME_OVERHEAD + PT_GPR10
-SP_R11       =  STACK_FRAME_OVERHEAD + PT_GPR11
-SP_R12       =  STACK_FRAME_OVERHEAD + PT_GPR12
-SP_R13       =  STACK_FRAME_OVERHEAD + PT_GPR13
-SP_R14       =  STACK_FRAME_OVERHEAD + PT_GPR14
-SP_R15       =  STACK_FRAME_OVERHEAD + PT_GPR15
-SP_AREGS     =  STACK_FRAME_OVERHEAD + PT_ACR0
-SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + PT_ORIGGPR2
-/* Now the additional entries */
-SP_ILC       =  (SP_ORIG_R2+GPR_SIZE)
-SP_TRAP      =  (SP_ILC+2)
-SP_SIZE      =  (SP_TRAP+2)
+SP_PSW       =  STACK_FRAME_OVERHEAD + __PT_PSW
+SP_R0        =  STACK_FRAME_OVERHEAD + __PT_GPRS
+SP_R1        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 4
+SP_R2        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 8
+SP_R3        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 12
+SP_R4        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 16
+SP_R5        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 20
+SP_R6        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 24
+SP_R7        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 28
+SP_R8        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 32
+SP_R9        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 36
+SP_R10       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 40
+SP_R11       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 44
+SP_R12       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 48
+SP_R13       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 52
+SP_R14       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 56
+SP_R15       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 60
+SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
+SP_ILC       =  STACK_FRAME_OVERHEAD + __PT_ILC
+SP_TRAP      =  STACK_FRAME_OVERHEAD + __PT_TRAP
+SP_SIZE      =  STACK_FRAME_OVERHEAD + __PT_SIZE
 
 _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_RESTART_SVC)
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
 
-/*
- * Base Address of this Module --- saved in __LC_ENTRY_BASE
- */
-       .globl entry_base
-entry_base:
-
-#define BASED(name) name-entry_base(%r13)
+#define BASED(name) name-system_call(%r13)
 
 /*
  * Register usage in interrupt handlers:
@@ -68,55 +60,108 @@
  *    R15 - kernel stack pointer
  */
 
-        .macro  SAVE_ALL_BASE
-        stm     %r13,%r15,__LC_SAVE_AREA
-        basr    %r13,0                    #  temp base pointer
-0:	stam    %a2,%a4,__LC_SAVE_AREA+12
-        l       %r13,.Lentry_base-0b(%r13)# load &entry_base to %r13
+        .macro  SAVE_ALL_BASE psworg,savearea,sync
+        stm     %r12,%r15,\savearea
+	l	%r13,__LC_SVC_NEW_PSW+4   # load &system_call to %r13
 	.endm
 
-        .macro  SAVE_ALL psworg,sync      # system entry macro
-        tm      \psworg+1,0x01            # test problem state bit
+        .macro  CLEANUP_SAVE_ALL_BASE psworg,savearea,sync
+	l	%r1,SP_PSW+4(%r15)
+	cli	1(%r1),0xcf
+	jne	0f
+	mvc	\savearea(16),SP_R12(%r15)
+0:	st	%r13,SP_R13(%r15)
+	.endm
+
+        .macro  SAVE_ALL psworg,savearea,sync
 	.if	\sync
+        tm      \psworg+1,0x01            # test problem state bit
         bz      BASED(1f)                 # skip stack setup save
+        l       %r15,__LC_KERNEL_STACK    # problem state -> load ksp
 	.else
-        bnz     BASED(0f)                 # from user -> load kernel stack
+        tm      \psworg+1,0x01            # test problem state bit
+        bnz     BASED(0f)                 # from user -> load async stack
 	l	%r14,__LC_ASYNC_STACK	  # are we already on the async stack ?
 	slr     %r14,%r15
 	sra	%r14,13
 	be	BASED(1f)
-        l       %r15,__LC_ASYNC_STACK     # load async. stack
-	b	BASED(1f)
+0:	l	%r15,__LC_ASYNC_STACK
 	.endif
-0:      l       %r15,__LC_KERNEL_STACK    # problem state -> load ksp
-	lam	%a2,%a4,BASED(.Lc_ac)	  # set ac.reg. 2 to primary space
-					  # and ac.reg. 4 to home space
 1:      s       %r15,BASED(.Lc_spsize)    # make room for registers & psw
-        n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
-        stm     %r0,%r12,SP_R0(%r15)      # store gprs 0-12 to kernel stack
+	l	%r14,BASED(.L\psworg)
+	slr	%r12,%r12
+	icm	%r14,12,__LC_SVC_ILC
+        stm     %r0,%r11,SP_R0(%r15)      # store gprs 0-12 to kernel stack
         st      %r2,SP_ORIG_R2(%r15)      # store original content of gpr 2
-        mvc     SP_R13(12,%r15),__LC_SAVE_AREA  # move R13-R15 to stack
-        stam    %a0,%a15,SP_AREGS(%r15)   # store access registers to kst.
-        mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
+        mvc     SP_R12(16,%r15),\savearea # move R13-R15 to stack
         mvc     SP_PSW(8,%r15),\psworg    # move user PSW to stack
-	mvc	SP_ILC(2,%r15),__LC_SVC_ILC      # store instruction length
-	mvc	SP_TRAP(2,%r15),BASED(.L\psworg) # store trap indication
-        xc      0(4,%r15),0(%r15)         # clear back chain
+	st	%r14,SP_ILC(%r15)
+        st      %r12,0(%r15)              # clear back chain
         .endm
 
-        .macro  RESTORE_ALL sync          # system exit macro
+	.macro	CLEANUP_SAVE_ALL psworg,savearea,sync
+	l	%r1,\savearea+12
+	.if	\sync
+	tm	\psworg+1,0x01
+	bz	BASED(1f)
+	l	%r1,__LC_KERNEL_STACK
+	.else
+	tm	\psworg+1,0x01
+	bnz	BASED(0f)
+	l	%r0,__LC_ASYNC_STACK
+	slr	%r0,%r1
+	sra	%r0,13
+	bz	BASED(1f)
+0:	l	%r1,__LC_ASYNC_STACK
+	.endif
+1:	s	%r1,BASED(.Lc_spsize)
+	st	%r1,SP_R15(%r15)
+	l	%r0,BASED(.L\psworg)
+	xc	SP_R12(4,%r15),SP_R12(%r15)
+	icm	%r0,12,__LC_SVC_ILC
+	st	%r0,SP_R14(%r15)
+	mvc	SP_R0(48,%r1),SP_R0(%r15)
+	mvc	SP_ORIG_R2(4,%r1),SP_R2(%r15)
+	mvc	SP_R12(16,%r1),\savearea
+	mvc	SP_PSW(8,%r1),\psworg
+	st	%r0,SP_ILC(%r1)
+	xc	0(4,%r1),0(%r1)
+	.endm
+
+        .macro  RESTORE_ALL               # system exit macro
         mvc     __LC_RETURN_PSW(8),SP_PSW(%r15)  # move user PSW to lowcore
-        lam     %a0,%a15,SP_AREGS(%r15)   # load the access registers
-        lm      %r0,%r15,SP_R0(%r15)      # load gprs 0-15 of user
         ni      __LC_RETURN_PSW+1,0xfd    # clear wait state bit
+        lm      %r0,%r15,SP_R0(%r15)      # load gprs 0-15 of user
         lpsw    __LC_RETURN_PSW           # back to caller
         .endm
 
+	.macro	CLEANUP_RESTORE_ALL
+	l	%r1,SP_PSW+4(%r15)
+	cli	0(%r1),0x82
+	jne	0f
+	mvc	SP_PSW(8,%r15),__LC_RETURN_PSW
+	j	1f
+0:	l	%r1,SP_R15(%r15)
+	mvc	SP_PSW(8,%r15),SP_PSW(%r1)
+	mvc	SP_R0(64,%r15),SP_R0(%r1)
+1:
+	.endm
+
         .macro  GET_THREAD_INFO
-	l	%r9,BASED(.Lc0xffffe000)  # load pointer to task_struct to %r9
-	al	%r9,__LC_KERNEL_STACK
+	l	%r9,__LC_THREAD_INFO
         .endm
 
+	.macro	CHECK_CRITICAL
+        tm      SP_PSW+1(%r15),0x01      # test problem state bit
+	bnz	BASED(0f)		 # from user -> not critical
+	clc	SP_PSW+4(4,%r15),BASED(.Lcritical_end)
+	jnl	0f
+	clc	SP_PSW+4(4,%r15),BASED(.Lcritical_start)
+	jl	0f
+	l	%r1,BASED(.Lcleanup_critical)
+	basr	%r14,%r1
+0:
+	.endm
 
 /*
  * Scheduler resume function, called by switch_to
@@ -139,13 +184,10 @@
         stm     %r6,%r15,24(%r15)       # store __switch_to registers of prev task
 	st	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
 	l	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
-	stam    %a2,%a2,__THREAD_ar2(%r2)	# store kernel access reg. 2
-	stam    %a4,%a4,__THREAD_ar4(%r2)	# store kernel access reg. 4
-	lam     %a2,%a2,__THREAD_ar2(%r3)	# load kernel access reg. 2
-	lam     %a4,%a4,__THREAD_ar4(%r3)	# load kernel access reg. 4
 	lm	%r6,%r15,24(%r15)	# load __switch_to registers of next task
 	st	%r3,__LC_CURRENT	# __LC_CURRENT = current task struct
 	l	%r3,__THREAD_info(%r3)  # load thread_info from task struct
+	st	%r3,__LC_THREAD_INFO
 	ahi	%r3,8192
 	st	%r3,__LC_KERNEL_STACK	# __LC_KERNEL_STACK = new kernel stack
 	br	%r14
@@ -172,6 +214,7 @@
 	lm	%r12,%r15,24(%r12)
 	br	%r14
 	
+__critical_start:
 /*
  * SVC interrupt handler routine. System calls are synchronous events and
  * are executed with interrupts enabled.
@@ -179,10 +222,10 @@
 
 	.globl  system_call
 system_call:
-	SAVE_ALL_BASE
-        SAVE_ALL __LC_SVC_OLD_PSW,1
+	SAVE_ALL_BASE __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
 	lh	%r7,0x8a	  # get svc number from lowcore
-        stosm   24(%r15),0x03     # reenable interrupts
+sysc_enter:
         GET_THREAD_INFO           # load pointer to task_struct to R9
 	sla	%r7,2             # *4 and test for svc 0
 	bnz	BASED(sysc_do_restart)  # svc number > 0
@@ -193,7 +236,7 @@
 	sla	%r7,2             # *4
 sysc_do_restart:
 	tm	__TI_flags+3(%r9),_TIF_SYSCALL_TRACE
-        l       %r8,sys_call_table-entry_base(%r7,%r13) # get system call addr.
+        l       %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
         bo      BASED(sysc_tracesys)
         basr    %r14,%r8          # call sys_xxxx
         st      %r2,SP_R2(%r15)   # store return value (change R2 on stack)
@@ -201,19 +244,17 @@
                                   # changing anything here !!
 
 sysc_return:
-	stnsm   24(%r15),0xfc     # disable I/O and ext. interrupts
 	tm	SP_PSW+1(%r15),0x01	# returning to user ?
 	bno	BASED(sysc_leave)
 	tm	__TI_flags+3(%r9),_TIF_WORK_SVC
 	bnz	BASED(sysc_work)  # there is work to do (signals etc.)
 sysc_leave:
-        RESTORE_ALL 1
+        RESTORE_ALL
 
 #
 # recheck if there is more work to do
 #
 sysc_work_loop:
-	stnsm   24(%r15),0xfc     # disable I/O and ext. interrupts
         GET_THREAD_INFO           # load pointer to task_struct to R9
 	tm	__TI_flags+3(%r9),_TIF_WORK_SVC
 	bz	BASED(sysc_leave)      # there is no work to do
@@ -234,7 +275,6 @@
 # _TIF_NEED_RESCHED is set, call schedule
 #	
 sysc_reschedule:        
-        stosm   24(%r15),0x03          # reenable interrupts
         l       %r1,BASED(.Lschedule)
 	la      %r14,BASED(sysc_work_loop)
 	br      %r1		       # call scheduler
@@ -243,12 +283,10 @@
 # _TIF_SIGPENDING is set, call do_signal
 #
 sysc_sigpending:     
-        stosm   24(%r15),0x03          # reenable interrupts
         la      %r2,SP_PTREGS(%r15)    # load pt_regs
         sr      %r3,%r3                # clear *oldset
         l       %r1,BASED(.Ldo_signal)
 	basr	%r14,%r1               # call do_signal
-        stnsm   24(%r15),0xfc          # disable I/O and ext. interrupts
 	tm	__TI_flags+3(%r9),_TIF_RESTART_SVC
 	bo	BASED(sysc_restart)
 	b	BASED(sysc_leave)      # out of here, do NOT recheck
@@ -258,13 +296,14 @@
 #
 sysc_restart:
 	ni	__TI_flags+3(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
-	stosm	24(%r15),0x03          # reenable interrupts
 	l	%r7,SP_R2(%r15)        # load new svc number
 	sla	%r7,2
 	mvc	SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
 	lm	%r2,%r6,SP_R2(%r15)    # load svc arguments
 	b	BASED(sysc_do_restart) # restart svc
 
+__critical_end:
+
 #
 # call trace before and after sys_call
 #
@@ -277,7 +316,7 @@
 	bnl	BASED(sysc_tracenogo)
 	l	%r7,SP_R2(%r15)        # strace might have changed the 
 	sll	%r7,2                  #  system call
-	l	%r8,sys_call_table-entry_base(%r7,%r13)
+	l	%r8,sys_call_table-system_call(%r7,%r13)
 sysc_tracego:
 	lm	%r3,%r6,SP_R3(%r15)
 	l	%r2,SP_ORIG_R2(%r15)
@@ -294,13 +333,13 @@
 # a new process exits the kernel with ret_from_fork
 #
         .globl  ret_from_fork
-ret_from_fork:  
-        basr    %r13,0
-        l       %r13,.Lentry_base-.(%r13)  # setup base pointer to &entry_base
+ret_from_fork:
+	l	%r13,__LC_SVC_NEW_PSW+4
         GET_THREAD_INFO           # load pointer to task_struct to R9
         l       %r1,BASED(.Lschedtail)
-	la      %r14,BASED(sysc_return)
-        br      %r1               # call schedule_tail, return to sysc_return
+	basr    %r14,%r1
+        stosm   24(%r15),0x03     # reenable interrupts
+	b	BASED(sysc_return)
 
 #
 # clone, fork, vfork, exec and sigreturn need glue,
@@ -373,12 +412,6 @@
         br      %r1                   # branch to sys_sigreturn
 
 
-#define SYSCALL(esa,esame,emu)	.long esa
-	.globl  sys_call_table
-sys_call_table:
-#include "syscalls.S"
-#undef SYSCALL
-
 /*
  * Program check handler routine
  */
@@ -398,10 +431,10 @@
  * we just ignore the PER event (FIXME: is there anything we have to do
  * for LPSW?).
  */
-	SAVE_ALL_BASE
+	SAVE_ALL_BASE __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         bnz     BASED(pgm_per)           # got per exception -> special case
-	SAVE_ALL __LC_PGM_OLD_PSW,1
+	SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
         l       %r3,__LC_PGM_ILC         # load program interruption code
 	la	%r8,0x7f
         l       %r7,BASED(.Ljump_table)
@@ -430,8 +463,11 @@
 # Normal per exception
 #
 pgm_per_std:
-	SAVE_ALL __LC_PGM_OLD_PSW,1
+	SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
 	GET_THREAD_INFO
+	mvc	__THREAD_per+__PER_atmid(2,%r9),__LC_PER_ATMID
+	mvc	__THREAD_per+__PER_address(4,%r9),__LC_PER_ADDRESS
+	mvc	__THREAD_per+__PER_access_id(1,%r9),__LC_PER_ACCESS_ID
 	la	%r4,0x7f
 	l	%r3,__LC_PGM_ILC	 # load program interruption code
         nr      %r4,%r3                  # clear per-event-bit and ilc
@@ -445,16 +481,19 @@
 	la      %r2,SP_PTREGS(15)	 # address of register-save area
         l       %r1,BASED(.Lhandle_per)  # load adr. of per handler
         la      %r14,BASED(sysc_return)  # load adr. of system return
-        br      %r1			 # branch to handle_per_exception
+        br      %r1			 # branch to do_debugger_trap
 
 #
 # it was a single stepped SVC that is causing all the trouble
 #
 pgm_svcper:
-	SAVE_ALL __LC_SVC_OLD_PSW,1
+	SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
 	lh	%r7,0x8a	  # get svc number from lowcore
         stosm   24(%r15),0x03     # reenable interrupts
         GET_THREAD_INFO           # load pointer to task_struct to R9
+	mvc	__THREAD_per+__PER_atmid(2,%r9),__LC_PER_ATMID
+	mvc	__THREAD_per+__PER_address(4,%r9),__LC_PER_ADDRESS
+	mvc	__THREAD_per+__PER_access_id(1,%r9),__LC_PER_ACCESS_ID
         sla     %r7,2             # *4 and test for svc 0
 	bnz	BASED(pgm_svcstd) # svc number > 0 ?
 	# svc 0: system call number in %r1
@@ -464,7 +503,7 @@
 	sla	%r7,2             # *4
 pgm_svcstd:
 	tm	__TI_flags+3(%r9),_TIF_SYSCALL_TRACE
-        l       %r8,sys_call_table-entry_base(%r7,%r13) # get system call addr.
+        l       %r8,sys_call_table-system_call(%r7,%r13) # get system call addr.
         bo      BASED(pgm_tracesys)
         basr    %r14,%r8          # call sys_xxxx
         st      %r2,SP_R2(%r15)   # store return value (change R2 on stack)
@@ -473,18 +512,18 @@
 
 pgm_svcret:
 	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
-	bo	BASED(pgm_svcper_nosig)
+	bno	BASED(pgm_svcper_nosig)
 	la	%r2,SP_PTREGS(%r15) # load pt_regs
 	sr	%r3,%r3		  # clear *oldset
 	l	%r1,BASED(.Ldo_signal)
-	basr	%r4,%r1		  # call do_signal
+	basr	%r14,%r1	  # call do_signal
 	
 pgm_svcper_nosig:
         mvi     SP_TRAP+3(%r15),0x28     # set trap indication to pgm check
 	la      %r2,SP_PTREGS(15)        # address of register-save area
         l       %r1,BASED(.Lhandle_per)  # load adr. of per handler
         la      %r14,BASED(sysc_return)  # load adr. of system return
-        br      %r1                      # branch to handle_per_exception
+        br      %r1                      # branch to do_debugger_trap
 #
 # call trace before and after sys_call
 #
@@ -497,7 +536,7 @@
 	bnl	BASED(pgm_svc_nogo)
 	l	%r7,SP_R2(%r15)   # strace changed the syscall
 	sll     %r7,2
-	l	%r8,sys_call_table-entry_base(%r7,%r13)
+	l	%r8,sys_call_table-system_call(%r7,%r13)
 pgm_svc_go:
 	lm      %r3,%r6,SP_R3(%r15)
 	l       %r2,SP_ORIG_R2(%r15)
@@ -516,10 +555,11 @@
 
         .globl io_int_handler
 io_int_handler:
-	SAVE_ALL_BASE
-        SAVE_ALL __LC_IO_OLD_PSW,0
-        GET_THREAD_INFO           # load pointer to task_struct to R9
+	SAVE_ALL_BASE __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
+        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
 	stck	__LC_INT_CLOCK
+	CHECK_CRITICAL
+        GET_THREAD_INFO           # load pointer to task_struct to R9
         l       %r1,BASED(.Ldo_IRQ)        # load address of do_IRQ
         la      %r2,SP_PTREGS(%r15) # address of register-save area
         basr    %r14,%r1          # branch to standard irq handler
@@ -534,24 +574,21 @@
 	tm	__TI_flags+3(%r9),_TIF_WORK_INT
 	bnz	BASED(io_work)         # there is work to do (signals etc.)
 io_leave:
-        RESTORE_ALL 0
+        RESTORE_ALL
 
 #ifdef CONFIG_PREEMPT
 io_preempt:
 	icm	%r0,15,__TI_precount(%r9)
 	bnz     BASED(io_leave)
-io_resume_loop:
-	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
-	bno	BASED(io_leave)
-	mvc     __TI_precount(4,%r9),BASED(.Lc_pactive)
-	# hmpf, we are on the async. stack but to call schedule
-	# we have to move the interrupt frame to the process stack
 	l	%r1,SP_R15(%r15)
 	s	%r1,BASED(.Lc_spsize)
-	n	%r1,BASED(.Lc0xfffffff8)
-	mvc	SP_PTREGS(SP_SIZE-SP_PTREGS,%r1),SP_PTREGS(%r15)
+	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
         xc      0(4,%r1),0(%r1)        # clear back chain
 	lr	%r15,%r1
+io_resume_loop:
+	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
+	bno	BASED(io_leave)
+	mvc     __TI_precount(4,%r9),BASED(.Lc_pactive)
         stosm   24(%r15),0x03          # reenable interrupts
         l       %r1,BASED(.Lschedule)
 	basr	%r14,%r1	       # call schedule
@@ -562,18 +599,19 @@
 #endif
 
 #
-# recheck if there is more work to do
+# switch to kernel stack, then check the TIF bits
 #
-io_work_loop:
-        stnsm   24(%r15),0xfc          # disable I/O and ext. interrupts
-        GET_THREAD_INFO                # load pointer to task_struct to R9
-	tm	__TI_flags+3(%r9),_TIF_WORK_INT
-	bz	BASED(io_leave)        # there is no work to do
+io_work:
+	l	%r1,__LC_KERNEL_STACK
+	s	%r1,BASED(.Lc_spsize)
+	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+        xc      0(4,%r1),0(%r1)        # clear back chain
+	lr	%r15,%r1
 #
 # One of the work bits is on. Find out which one.
 # Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
 #
-io_work:
+io_work_loop:
 	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
 	bo	BASED(io_reschedule)
 	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
@@ -584,10 +622,14 @@
 # _TIF_NEED_RESCHED is set, call schedule
 #	
 io_reschedule:        
-        stosm   24(%r15),0x03          # reenable interrupts
         l       %r1,BASED(.Lschedule)
-	la      %r14,BASED(io_work_loop)
-	br      %r1		       # call scheduler
+        stosm   24(%r15),0x03          # reenable interrupts
+	basr    %r14,%r1	       # call scheduler
+        stnsm   24(%r15),0xfc          # disable I/O and ext. interrupts
+        GET_THREAD_INFO                # load pointer to task_struct to R9
+	tm	__TI_flags+3(%r9),_TIF_WORK_INT
+	bz	BASED(io_leave)        # there is no work to do
+	b	BASED(io_work_loop)
 
 #
 # _TIF_SIGPENDING is set, call do_signal
@@ -607,10 +649,11 @@
 
         .globl  ext_int_handler
 ext_int_handler:
-	SAVE_ALL_BASE
-        SAVE_ALL __LC_EXT_OLD_PSW,0
-        GET_THREAD_INFO                # load pointer to task_struct to R9
+	SAVE_ALL_BASE __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
+        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
 	stck	__LC_INT_CLOCK
+	CHECK_CRITICAL
+        GET_THREAD_INFO                # load pointer to task_struct to R9
 	la	%r2,SP_PTREGS(%r15)    # address of register-save area
 	lh	%r3,__LC_EXT_INT_CODE  # get interruption code
 	l	%r1,BASED(.Ldo_extint)
@@ -623,12 +666,12 @@
 
         .globl mcck_int_handler
 mcck_int_handler:
-	SAVE_ALL_BASE
-        SAVE_ALL __LC_MCK_OLD_PSW,0
+	SAVE_ALL_BASE __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0
+        SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0
 	l       %r1,BASED(.Ls390_mcck)
 	basr    %r14,%r1	  # call machine check handler
 mcck_return:
-        RESTORE_ALL 0
+        RESTORE_ALL
 
 #ifdef CONFIG_SMP
 /*
@@ -661,24 +704,65 @@
 restart_go:
 #endif
 
+cleanup_table:
+	.long	system_call, sysc_enter, cleanup_sysc_enter
+	.long	sysc_return, sysc_leave, cleanup_sysc_return
+	.long	sysc_leave, sysc_work_loop, cleanup_sysc_leave
+	.long	sysc_work_loop, sysc_reschedule, cleanup_sysc_return
+cleanup_table_entries=(.-cleanup_table) / 12
+
+cleanup_critical:
+	lhi	%r0,cleanup_table_entries
+	la	%r1,BASED(cleanup_table)
+	l	%r2,SP_PSW+4(%r15)
+	la	%r2,0(%r2)
+cleanup_loop:
+	cl	%r2,0(%r1)
+	bl	BASED(cleanup_cont)
+	cl	%r2,4(%r1)
+	bl	BASED(cleanup_found)
+cleanup_cont:
+	la	%r1,12(%r1)
+	bct	%r0,BASED(cleanup_loop)
+	br	%r14
+cleanup_found:
+	l	%r1,8(%r1)
+	br	%r1
+
+cleanup_sysc_enter:
+	CLEANUP_SAVE_ALL_BASE __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+	CLEANUP_SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+	lh	%r0,0x8a
+	st	%r0,SP_R7(%r15)
+	la	%r1,BASED(sysc_enter)
+	o	%r1,BASED(.Lamode)
+	st	%r1,SP_PSW+4(%r15)
+	br	%r14
+
+cleanup_sysc_return:
+	la	%r1,BASED(sysc_return)
+	o	%r1,BASED(.Lamode)
+	st	%r1,SP_PSW+4(%r15)
+	br	%r14
+
+cleanup_sysc_leave:
+	CLEANUP_RESTORE_ALL
+	br	%r14
+
 /*
  * Integer constants
  */
                .align 4
-.Lc0xfffffff8: .long  -8           # to align stack pointer to 8
-.Lc0xffffe000: .long  -8192        # to round stack pointer to &task_struct
 .Lc_spsize:    .long  SP_SIZE
 .Lc_overhead:  .long  STACK_FRAME_OVERHEAD
-.Lc_ac:        .long  0,0,1
-.Lc_ENOSYS:    .long  -ENOSYS
 .Lc_pactive:   .long  PREEMPT_ACTIVE
-.Lc0xff:       .long  0xff
 .Lnr_syscalls: .long  NR_syscalls
-.L0x018:       .word  0x018
-.L0x020:       .word  0x020
-.L0x028:       .word  0x028
-.L0x030:       .word  0x030
-.L0x038:       .word  0x038
+.L0x018:       .long  0x018
+.L0x020:       .long  0x020
+.L0x028:       .long  0x028
+.L0x030:       .long  0x030
+.L0x038:       .long  0x038
+.Lamode:       .long  0x80000000
 
 /*
  * Symbol constants
@@ -688,9 +772,7 @@
 .Ldo_extint:   .long  do_extint
 .Ldo_signal:   .long  do_signal
 .Ldo_softirq:  .long  do_softirq
-.Lentry_base:  .long  entry_base
-.Lext_hash:    .long  ext_int_hash
-.Lhandle_per:  .long  handle_per_exception
+.Lhandle_per:  .long  do_debugger_trap
 .Ljump_table:  .long  pgm_check_table
 .Lschedule:    .long  schedule
 .Lclone:       .long  sys_clone
@@ -706,4 +788,16 @@
 .Lvfork:       .long  sys_vfork
 .Lschedtail:   .long  schedule_tail
 
+.Lcritical_start:
+               .long  __critical_start + 0x80000000
+.Lcritical_end:
+               .long  __critical_end + 0x80000000
+.Lcleanup_critical:
+               .long  cleanup_critical
+
+#define SYSCALL(esa,esame,emu)	.long esa
+	.globl  sys_call_table
+sys_call_table:
+#include "syscalls.S"
+#undef SYSCALL
 
diff -Nru a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
--- a/arch/s390/kernel/entry64.S	Sat Apr  3 19:38:41 2004
+++ b/arch/s390/kernel/entry64.S	Sat Apr  3 19:38:41 2004
@@ -25,29 +25,27 @@
  * The first few entries are identical to the user_regs_struct.
  */
 SP_PTREGS    =  STACK_FRAME_OVERHEAD 
-SP_PSW       =  STACK_FRAME_OVERHEAD + PT_PSWMASK
-SP_R0        =  STACK_FRAME_OVERHEAD + PT_GPR0
-SP_R1        =  STACK_FRAME_OVERHEAD + PT_GPR1
-SP_R2        =  STACK_FRAME_OVERHEAD + PT_GPR2
-SP_R3        =  STACK_FRAME_OVERHEAD + PT_GPR3
-SP_R4        =  STACK_FRAME_OVERHEAD + PT_GPR4
-SP_R5        =  STACK_FRAME_OVERHEAD + PT_GPR5
-SP_R6        =  STACK_FRAME_OVERHEAD + PT_GPR6
-SP_R7        =  STACK_FRAME_OVERHEAD + PT_GPR7
-SP_R8        =  STACK_FRAME_OVERHEAD + PT_GPR8
-SP_R9        =  STACK_FRAME_OVERHEAD + PT_GPR9
-SP_R10       =  STACK_FRAME_OVERHEAD + PT_GPR10
-SP_R11       =  STACK_FRAME_OVERHEAD + PT_GPR11
-SP_R12       =  STACK_FRAME_OVERHEAD + PT_GPR12
-SP_R13       =  STACK_FRAME_OVERHEAD + PT_GPR13
-SP_R14       =  STACK_FRAME_OVERHEAD + PT_GPR14
-SP_R15       =  STACK_FRAME_OVERHEAD + PT_GPR15
-SP_AREGS     =  STACK_FRAME_OVERHEAD + PT_ACR0
-SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + PT_ORIGGPR2
-/* Now the additional entries */
-SP_ILC       =  (SP_ORIG_R2+GPR_SIZE)
-SP_TRAP      =  (SP_ILC+2)
-SP_SIZE      =  (SP_TRAP+2)
+SP_PSW       =  STACK_FRAME_OVERHEAD + __PT_PSW
+SP_R0        =  STACK_FRAME_OVERHEAD + __PT_GPRS
+SP_R1        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 8
+SP_R2        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 16
+SP_R3        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 24
+SP_R4        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 32
+SP_R5        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 40
+SP_R6        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 48
+SP_R7        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 56
+SP_R8        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 64
+SP_R9        =  STACK_FRAME_OVERHEAD + __PT_GPRS + 72
+SP_R10       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 80
+SP_R11       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 88
+SP_R12       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 96
+SP_R13       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 104
+SP_R14       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 112
+SP_R15       =  STACK_FRAME_OVERHEAD + __PT_GPRS + 120
+SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
+SP_ILC       =  STACK_FRAME_OVERHEAD + __PT_ILC
+SP_TRAP      =  STACK_FRAME_OVERHEAD + __PT_TRAP
+SP_SIZE      =  STACK_FRAME_OVERHEAD + __PT_SIZE
 
 _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_RESTART_SVC)
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
@@ -60,51 +58,100 @@
  *    R15 - kernel stack pointer
  */
 
-        .macro  SAVE_ALL psworg,sync     # system entry macro
-        stmg    %r14,%r15,__LC_SAVE_AREA
-	stam    %a2,%a4,__LC_SAVE_AREA+16
-	larl	%r14,.Lconst
-        tm      \psworg+1,0x01           # test problem state bit
+        .macro  SAVE_ALL psworg,savearea,sync
+        stmg    %r13,%r15,\savearea
 	.if	\sync
+        tm      \psworg+1,0x01           # test problem state bit
         jz      1f                       # skip stack setup save
+	lg      %r15,__LC_KERNEL_STACK   # problem state -> load ksp
 	.else
+        tm      \psworg+1,0x01           # test problem state bit
 	jnz	0f			 # from user -> load kernel stack
 	lg	%r14,__LC_ASYNC_STACK	 # are we already on the async. stack ?
 	slgr	%r14,%r15
 	srag	%r14,%r14,14
-	larl	%r14,.Lconst
 	jz	1f
-	lg	%r15,__LC_ASYNC_STACK	 # load async. stack
-	j	1f
+0:	lg      %r15,__LC_ASYNC_STACK    # load async stack
 	.endif
-0:	lg      %r15,__LC_KERNEL_STACK   # problem state -> load ksp
-	lam	%a2,%a4,.Lc_ac-.Lconst(%r14)
 1:      aghi    %r15,-SP_SIZE            # make room for registers & psw
-        nill    %r15,0xfff8              # align stack pointer to 8
-        stmg    %r0,%r13,SP_R0(%r15)     # store gprs 0-13 to kernel stack
+	lghi	%r14,\psworg
+	slgr	%r13,%r13
+	icm	%r14,12,__LC_SVC_ILC
+        stmg    %r0,%r12,SP_R0(%r15)     # store gprs 0-13 to kernel stack
         stg     %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_R14(16,%r15),__LC_SAVE_AREA # move r14 and r15 to stack
-        stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
-        mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+16 # store ac. regs
+        mvc     SP_R13(24,%r15),\savearea # move r13, r14 and r15 to stack
         mvc     SP_PSW(16,%r15),\psworg  # move user PSW to stack
-	mvc	SP_ILC(2,%r15),__LC_SVC_ILC # store instruction length
-	mvc	SP_TRAP(2,%r15),.L\psworg-.Lconst(%r14) # store trap ind.
-        xc      0(8,%r15),0(%r15)        # clear back chain
+	st	%r14,SP_ILC(%r15)
+	stg	%r13,0(%r15)
         .endm
 
-        .macro  RESTORE_ALL sync         # system exit macro
+	.macro	CLEANUP_SAVE_ALL psworg,savearea,sync
+	lg	%r1,SP_PSW+8(%r15)
+	cli	1(%r1),0xdf
+	jne	2f
+	mvc	\savearea(24),SP_R13(%r15)
+2:	lg	%r1,\savearea+16
+	.if	\sync
+	tm	\psworg+1,0x01
+	jz	1f
+	lg	%r1,__LC_KERNEL_STACK
+	.else
+	tm	\psworg+1,0x01
+	jnz	0f
+	lg	%r0,__LC_ASYNC_STACK
+	slgr	%r0,%r1
+	srag	%r0,%r0,14
+	jz	1f
+0:	lg	%r1,__LC_ASYNC_STACK
+	.endif
+1:	aghi	%r1,-SP_SIZE
+	stg	%r1,SP_R15(%r15)
+	lghi	%r0,\psworg
+	xc	SP_R13(8,%r15),SP_R13(%r15)
+	icm	%r0,12,__LC_SVC_ILC
+	stg	%r0,SP_R14(%r15)
+	mvc	SP_R0(104,%r1),SP_R0(%r15)
+	mvc	SP_ORIG_R2(8,%r1),SP_R2(%r15)
+	mvc	SP_R13(24,%r1),\savearea
+	mvc	SP_PSW(16,%r1),\psworg
+	st	%r0,SP_ILC(%r1)
+	xc	0(8,%r1),0(%r1)
+	.endm
+
+        .macro  RESTORE_ALL              # system exit macro
         mvc     __LC_RETURN_PSW(16),SP_PSW(%r15) # move user PSW to lowcore
-        lam     %a0,%a15,SP_AREGS(%r15)  # load the access registers
-        lmg     %r0,%r15,SP_R0(%r15)     # load gprs 0-15 of user
         ni      __LC_RETURN_PSW+1,0xfd   # clear wait state bit
+        lmg     %r0,%r15,SP_R0(%r15)     # load gprs 0-15 of user
         lpswe   __LC_RETURN_PSW          # back to caller
         .endm
 
+	.macro	CLEANUP_RESTORE_ALL
+	lg	%r1,SP_PSW+8(%r15)
+	cli	0(%r1),0xb2
+	jne	0f
+	mvc	SP_PSW(16,%r15),__LC_RETURN_PSW
+	j	1f
+0:	lg	%r1,SP_R15(%r15)
+	mvc	SP_PSW(16,%r15),SP_PSW(%r1)
+	mvc	SP_R0(128,%r15),SP_R0(%r1)
+1:
+	.endm
+
         .macro  GET_THREAD_INFO
-	lg	%r9,__LC_KERNEL_STACK    # load pointer to task_struct to %r9
-	aghi	%r9,-16384
+	lg	%r9,__LC_THREAD_INFO     # load pointer to thread_info struct
         .endm
 
+	.macro	CHECK_CRITICAL
+        tm      SP_PSW+1(%r15),0x01      # test problem state bit
+	jnz	0f			 # from user -> not critical
+	larl	%r1,.Lcritical_start
+	clc	SP_PSW+8(8,%r15),8(%r1)  # compare ip with __critical_end
+	jnl	0f
+	clc	SP_PSW+8(8,%r15),0(%r1)  # compare ip with __critical_start
+	jl	0f
+	brasl	%r14,cleanup_critical
+0:
+	.endm
 
 /*
  * Scheduler resume function, called by switch_to
@@ -125,13 +172,10 @@
         stmg    %r6,%r15,48(%r15)       # store __switch_to registers of prev task
 	stg	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
 	lg	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
-        stam    %a2,%a2,__THREAD_ar2(%r2)	# store kernel access reg. 2
-        stam    %a4,%a4,__THREAD_ar4(%r2)	# store kernel access reg. 4
-        lam     %a2,%a2,__THREAD_ar2(%r3)	# load kernel access reg. 2
-        lam     %a4,%a4,__THREAD_ar4(%r3)	# load kernel access reg. 4
         lmg     %r6,%r15,48(%r15)       # load __switch_to registers of next task
 	stg	%r3,__LC_CURRENT	# __LC_CURRENT = current task struct
 	lg	%r3,__THREAD_info(%r3)  # load thread_info from task struct
+	stg	%r3,__LC_THREAD_INFO
 	aghi	%r3,16384
 	stg	%r3,__LC_KERNEL_STACK	# __LC_KERNEL_STACK = new kernel stack
 	br	%r14
@@ -154,7 +198,8 @@
 	brasl	%r14,do_softirq
 	lmg	%r12,%r15,48(%r12)
 	br	%r14
-	
+
+__critical_start:
 /*
  * SVC interrupt handler routine. System calls are synchronous events and
  * are executed with interrupts enabled.
@@ -162,14 +207,15 @@
 
 	.globl  system_call
 system_call:
-        SAVE_ALL __LC_SVC_OLD_PSW,1
+        SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
 	llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
-	stosm   48(%r15),0x03     # reenable interrupts
+sysc_enter:
         GET_THREAD_INFO           # load pointer to task_struct to R9
         slag    %r7,%r7,2         # *4 and test for svc 0
 	jnz	sysc_do_restart
 	# svc 0: system call number in %r1
-	cl	%r1,.Lnr_syscalls-.Lconst(%r14)
+	lghi	%r0,NR_syscalls
+	clr	%r1,%r0
 	jnl	sysc_do_restart
 	lgfr	%r7,%r1           # clear high word in r1
 	slag    %r7,%r7,2         # svc 0: system call number in %r1
@@ -190,19 +236,17 @@
                                   # changing anything here !!
 
 sysc_return:
-	stnsm   48(%r15),0xfc     # disable I/O and ext. interrupts
         tm      SP_PSW+1(%r15),0x01    # returning to user ?
         jno     sysc_leave
 	tm	__TI_flags+7(%r9),_TIF_WORK_SVC
 	jnz	sysc_work         # there is work to do (signals etc.)
 sysc_leave:
-        RESTORE_ALL 1
+        RESTORE_ALL
 
 #
 # recheck if there is more work to do
 #
 sysc_work_loop:
-	stnsm   48(%r15),0xfc     # disable I/O and ext. interrupts
         GET_THREAD_INFO           # load pointer to task_struct to R9
 	tm	__TI_flags+7(%r9),_TIF_WORK_SVC
 	jz	sysc_leave        # there is no work to do
@@ -223,7 +267,6 @@
 # _TIF_NEED_RESCHED is set, call schedule
 #	
 sysc_reschedule:        
-	stosm   48(%r15),0x03     # reenable interrupts
 	larl    %r14,sysc_work_loop
         jg      schedule            # return point is sysc_return
 
@@ -231,11 +274,9 @@
 # _TIF_SIGPENDING is set, call do_signal
 #
 sysc_sigpending:     
-	stosm   48(%r15),0x03     # reenable interrupts
         la      %r2,SP_PTREGS(%r15) # load pt_regs
         sgr     %r3,%r3           # clear *oldset
 	brasl	%r14,do_signal    # call do_signal
-	stnsm   48(%r15),0xfc     # disable I/O and ext. interrupts
 	tm	__TI_flags+7(%r9),_TIF_RESTART_SVC
 	jo	sysc_restart
 	j	sysc_leave        # out of here, do NOT recheck
@@ -245,13 +286,14 @@
 #
 sysc_restart:
 	ni	__TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
-	stosm	48(%r15),0x03          # reenable interrupts
 	lg	%r7,SP_R2(%r15)        # load new svc number
         slag    %r7,%r7,2              # *4
 	mvc	SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument
 	lmg	%r2,%r6,SP_R2(%r15)    # load svc arguments
 	j	sysc_do_restart        # restart svc
 
+__critical_end:
+
 #
 # call syscall_trace before and after system call
 # special linkage: %r12 contains the return address for trace_svc
@@ -260,9 +302,9 @@
 	srl	%r7,2
 	stg     %r7,SP_R2(%r15)
         brasl   %r14,syscall_trace
-	larl	%r1,.Lnr_syscalls
-	clc	SP_R2(8,%r15),0(%r1)
-	jnl	sysc_tracenogo
+	lghi	%r0,NR_syscalls
+	clg	%r0,SP_R2(%r15)
+	jnh	sysc_tracenogo
 	lg	%r7,SP_R2(%r15)   # strace might have changed the
 	sll     %r7,2             #  system call
 	lgf	%r8,0(%r7,%r10)
@@ -283,8 +325,9 @@
         .globl  ret_from_fork
 ret_from_fork:  
         GET_THREAD_INFO           # load pointer to task_struct to R9
-	larl    %r14,sysc_return
-        jg      schedule_tail     # return to sysc_return
+        brasl   %r14,schedule_tail
+        stosm   24(%r15),0x03     # reenable interrupts
+	j	sysc_return
 
 #
 # clone, fork, vfork, exec and sigreturn need glue,
@@ -405,21 +448,6 @@
         jg      sys32_sigaltstack_wrapper # branch to sys_sigreturn
 #endif
 
-#define SYSCALL(esa,esame,emu)	.long esame
-	.globl  sys_call_table	
-sys_call_table:
-#include "syscalls.S"
-#undef SYSCALL
-
-#ifdef CONFIG_S390_SUPPORT
-
-#define SYSCALL(esa,esame,emu)	.long emu
-	.globl  sys_call_table_emu
-sys_call_table_emu:
-#include "syscalls.S"
-#undef SYSCALL
-#endif
-
 /*
  * Program check handler routine
  */
@@ -441,7 +469,7 @@
  */
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
         jnz     pgm_per                  # got per exception -> special case
-	SAVE_ALL __LC_PGM_OLD_PSW,1
+	SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
 	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
 	lghi	%r8,0x7f
 	ngr	%r8,%r3
@@ -469,8 +497,11 @@
 # Normal per exception
 #
 pgm_per_std:
-	SAVE_ALL __LC_PGM_OLD_PSW,1
+	SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
 	GET_THREAD_INFO
+	mvc	__THREAD_per+__PER_atmid(2,%r9),__LC_PER_ATMID
+	mvc	__THREAD_per+__PER_address(8,%r9),__LC_PER_ADDRESS
+	mvc	__THREAD_per+__PER_access_id(1,%r9),__LC_PER_ACCESS_ID
 	lghi    %r4,0x7f
 	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
         nr      %r4,%r3			 # clear per-event-bit and ilc
@@ -483,20 +514,24 @@
 pgm_per_only:
         la      %r2,SP_PTREGS(15)	 # address of register-save area
         larl    %r14,sysc_return	 # load adr. of system return
-        jg      handle_per_exception
+        jg      do_debugger_trap
 
 #
 # it was a single stepped SVC that is causing all the trouble
 #
 pgm_svcper:
-	SAVE_ALL __LC_SVC_OLD_PSW,1
+	SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
 	llgh    %r7,__LC_SVC_INT_CODE # get svc number from lowcore
 	stosm   48(%r15),0x03     # reenable interrupts
         GET_THREAD_INFO           # load pointer to task_struct to R9
+	mvc	__THREAD_per+__PER_atmid(2,%r9),__LC_PER_ATMID
+	mvc	__THREAD_per+__PER_address(8,%r9),__LC_PER_ADDRESS
+	mvc	__THREAD_per+__PER_access_id(1,%r9),__LC_PER_ACCESS_ID
 	slag	%r7,%r7,2         # *4 and test for svc 0
 	jnz	pgm_svcstd
 	# svc 0: system call number in %r1
-	clg	%r1,.Lnr_syscalls-.Lconst(%r14)
+	lghi	%r0,NR_syscalls
+	clr	%r1,%r0
 	slag	%r7,%r1,2
 pgm_svcstd:
 	larl    %r10,sys_call_table
@@ -516,7 +551,7 @@
 
 pgm_svcret:
 	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
-	jo	pgm_svcper_nosig
+	jno	pgm_svcper_nosig
         la      %r2,SP_PTREGS(%r15) # load pt_regs
         sgr     %r3,%r3             # clear *oldset
 	brasl	%r14,do_signal
@@ -526,7 +561,7 @@
 	st      %r0,SP_TRAP(%r15)
         la      %r2,SP_PTREGS(15) # address of register-save area
         larl    %r14,sysc_return  # load adr. of system return
-        jg      handle_per_exception
+        jg      do_debugger_trap
 #
 # call trace before and after sys_call
 #
@@ -534,8 +569,9 @@
 	srlg	%r7,%r7,2
 	stg	%r7,SP_R2(%r15)
         brasl   %r14,syscall_trace
-	clc	SP_R2(8,%r15),.Lnr_syscalls
-	jnl     pgm_svc_nogo
+	lghi	%r0,NR_syscalls
+	clg	%r0,SP_R2(%r15)
+	jnh	pgm_svc_nogo
 	lg      %r7,SP_R2(%r15)
 	sllg    %r7,%r7,2           # strace wants to change the syscall
 	lgf	%r8,0(%r7,%r10)
@@ -555,9 +591,10 @@
  */
         .globl io_int_handler
 io_int_handler:
-        SAVE_ALL __LC_IO_OLD_PSW,0
-        GET_THREAD_INFO                # load pointer to task_struct to R9
+        SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
 	stck	__LC_INT_CLOCK
+	CHECK_CRITICAL
+        GET_THREAD_INFO                # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
 	brasl   %r14,do_IRQ            # call standard irq handler
 
@@ -571,25 +608,23 @@
 	tm	__TI_flags+7(%r9),_TIF_WORK_INT
 	jnz	io_work                # there is work to do (signals etc.)
 io_leave:
-        RESTORE_ALL 0
+        RESTORE_ALL
 
 #ifdef CONFIG_PREEMPT
 io_preempt:
 	icm	%r0,15,__TI_precount(%r9)	
 	jnz     io_leave
+	# switch to kernel stack
+	lg	%r1,SP_R15(%r15)
+	aghi	%r1,-SP_SIZE
+	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+        xc      0(8,%r1),0(%r1)        # clear back chain
+	lgr	%r15,%r1
 io_resume_loop:
 	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
 	jno	io_leave
 	larl    %r1,.Lc_pactive
 	mvc     __TI_precount(4,%r9),0(%r1)
-	# hmpf, we are on the async. stack but to call schedule
-	# we have to move the interrupt frame to the process stack
-	lg	%r1,SP_R15(%r15)
-	aghi	%r1,-SP_SIZE
-	nill	%r1,0xfff8
-	mvc	SP_PTREGS(SP_SIZE-SP_PTREGS,%r1),SP_PTREGS(%r15)
-        xc      0(8,%r1),0(%r1)        # clear back chain
-	lgr	%r15,%r1
         stosm   48(%r15),0x03          # reenable interrupts
 	brasl   %r14,schedule          # call schedule
         stnsm   48(%r15),0xfc          # disable I/O and ext. interrupts
@@ -599,18 +634,19 @@
 #endif
 
 #
-# recheck if there is more work to do
+# switch to kernel stack, then check TIF bits
 #
-io_work_loop:
-        stnsm   48(%r15),0xfc          # disable I/O and ext. interrupts
-        GET_THREAD_INFO                # load pointer to task_struct to R9
-	tm	__TI_flags+7(%r9),_TIF_WORK_INT
-	jz	io_leave               # there is no work to do
+io_work:
+	lg	%r1,__LC_KERNEL_STACK
+	aghi	%r1,-SP_SIZE
+	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+        xc      0(8,%r1),0(%r1)        # clear back chain
+	lgr	%r15,%r1
 #
 # One of the work bits is on. Find out which one.
 # Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
 #
-io_work:
+io_work_loop:
 	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
 	jo	io_reschedule
 	tm	__TI_flags+7(%r9),_TIF_SIGPENDING
@@ -622,8 +658,12 @@
 #	
 io_reschedule:        
         stosm   48(%r15),0x03       # reenable interrupts
-	larl    %r14,io_work_loop
-        jg      schedule            # call scheduler
+        brasl   %r14,schedule       # call scheduler
+        stnsm   48(%r15),0xfc       # disable I/O and ext. interrupts
+        GET_THREAD_INFO             # load pointer to task_struct to R9
+	tm	__TI_flags+7(%r9),_TIF_WORK_INT
+	jz	io_leave               # there is no work to do
+	j	io_work_loop
 
 #
 # _TIF_SIGPENDING is set, call do_signal
@@ -641,7 +681,8 @@
  */
         .globl  ext_int_handler
 ext_int_handler:
-        SAVE_ALL __LC_EXT_OLD_PSW,0
+        SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
+	CHECK_CRITICAL
         GET_THREAD_INFO                # load pointer to task_struct to R9
 	stck	__LC_INT_CLOCK
 	la	%r2,SP_PTREGS(%r15)    # address of register-save area
@@ -654,10 +695,10 @@
  */
         .globl mcck_int_handler
 mcck_int_handler:
-        SAVE_ALL __LC_MCK_OLD_PSW,0
+        SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0
 	brasl   %r14,s390_do_machine_check
 mcck_return:
-        RESTORE_ALL 0
+        RESTORE_ALL
 
 #ifdef CONFIG_SMP
 /*
@@ -688,16 +729,69 @@
 restart_go:
 #endif
 
+cleanup_table:
+	.quad	system_call, sysc_enter, cleanup_sysc_enter
+	.quad	sysc_return, sysc_leave, cleanup_sysc_return
+	.quad	sysc_leave, sysc_work_loop, cleanup_sysc_leave
+	.quad	sysc_work_loop, sysc_reschedule, cleanup_sysc_return
+cleanup_table_entries=(.-cleanup_table) / 24
+
+cleanup_critical:
+	lghi	%r0,cleanup_table_entries
+	larl	%r1,cleanup_table
+	lg	%r2,SP_PSW+8(%r15)
+cleanup_loop:
+	clg	%r2,0(%r1)
+	jl	cleanup_cont
+	clg	%r2,8(%r1)
+	jl	cleanup_found
+cleanup_cont:
+	la	%r1,24(%r1)
+	brct	%r0,cleanup_loop
+	br	%r14
+cleanup_found:
+	lg	%r1,16(%r1)
+	br	%r1
+
+cleanup_sysc_enter:
+	CLEANUP_SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+	llgh	%r0,0x8a
+	stg	%r0,SP_R7(%r15)
+	larl	%r1,sysc_enter
+	stg	%r1,SP_PSW+8(%r15)
+	br	%r14
+
+cleanup_sysc_return:
+	larl	%r1,sysc_return
+	stg	%r1,SP_PSW+8(%r15)
+	br	%r14
+
+cleanup_sysc_leave:
+	CLEANUP_RESTORE_ALL
+	br	%r14
+
 /*
  * Integer constants
  */
                .align 4
 .Lconst:
-.Lc_ac:        .long  0,0,1
 .Lc_pactive:   .long  PREEMPT_ACTIVE
-.L0x0130:      .word  0x0130
-.L0x0140:      .word  0x0140
-.L0x0150:      .word  0x0150
-.L0x0160:      .word  0x0160
-.L0x0170:      .word  0x0170
-.Lnr_syscalls: .long  NR_syscalls
+.Lcritical_start:
+               .quad  __critical_start
+.Lcritical_end:
+               .quad  __critical_end
+
+#define SYSCALL(esa,esame,emu)	.long esame
+	.globl  sys_call_table
+sys_call_table:
+#include "syscalls.S"
+#undef SYSCALL
+
+#ifdef CONFIG_S390_SUPPORT
+
+#define SYSCALL(esa,esame,emu)	.long emu
+	.globl  sys_call_table_emu
+sys_call_table_emu:
+#include "syscalls.S"
+#undef SYSCALL
+#endif
diff -Nru a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
--- a/arch/s390/kernel/process.c	Sat Apr  3 19:38:54 2004
+++ b/arch/s390/kernel/process.c	Sat Apr  3 19:38:54 2004
@@ -179,7 +179,7 @@
 	memset(&regs, 0, sizeof(regs));
 	regs.psw.mask = PSW_KERNEL_BITS;
 	regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
-	regs.gprs[7] = STACK_FRAME_OVERHEAD;
+	regs.gprs[7] = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
 	regs.gprs[8] = __LC_KERNEL_STACK;
 	regs.gprs[9] = (unsigned long) fn;
 	regs.gprs[10] = (unsigned long) arg;
@@ -230,6 +230,7 @@
 		 (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
         p->thread.ksp = (unsigned long) frame;
 	p->set_child_tid = p->clear_child_tid = NULL;
+	/* Store access registers to kernel stack of new process. */
         frame->childregs = *regs;
 	frame->childregs.gprs[2] = 0;	/* child returns 0 on fork. */
         frame->childregs.gprs[15] = new_stackp;
@@ -240,6 +241,10 @@
 
         /* fake return stack for resume(), don't go back to schedule */
         frame->gprs[9] = (unsigned long) frame;
+
+	/* Save access registers to new thread structure. */
+	save_access_regs(&p->thread.acrs[0]);
+
 #ifndef CONFIG_ARCH_S390X
         /*
 	 * save fprs to current->thread.fp_regs to merge them with
@@ -251,7 +256,7 @@
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
 	/* Set a new TLS ?  */
 	if (clone_flags & CLONE_SETTLS)
-		frame->childregs.acrs[0] = regs->gprs[6];
+		p->thread.acrs[0] = regs->gprs[6];
 #else /* CONFIG_ARCH_S390X */
 	/* Save the fpu registers to new thread structure. */
 	save_fp_regs(&p->thread.fp_regs);
@@ -259,30 +264,27 @@
 	/* Set a new TLS ?  */
 	if (clone_flags & CLONE_SETTLS) {
 		if (test_thread_flag(TIF_31BIT)) {
-			frame->childregs.acrs[0] =
-				(unsigned int) regs->gprs[6];
+			p->thread.acrs[0] = (unsigned int) regs->gprs[6];
 		} else {
-			frame->childregs.acrs[0] =
-				(unsigned int)(regs->gprs[6] >> 32);
-			frame->childregs.acrs[1] =
-				(unsigned int) regs->gprs[6];
+			p->thread.acrs[0] = (unsigned int)(regs->gprs[6] >> 32);
+			p->thread.acrs[1] = (unsigned int) regs->gprs[6];
 		}
 	}
 #endif /* CONFIG_ARCH_S390X */
 	/* start new process with ar4 pointing to the correct address space */
-	p->thread.ar4 = get_fs().ar4;
+	p->thread.mm_segment = get_fs();
         /* Don't copy debug registers */
         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
 
         return 0;
 }
 
-asmlinkage int sys_fork(struct pt_regs regs)
+asmlinkage long sys_fork(struct pt_regs regs)
 {
 	return do_fork(SIGCHLD, regs.gprs[15], &regs, 0, NULL, NULL);
 }
 
-asmlinkage int sys_clone(struct pt_regs regs)
+asmlinkage long sys_clone(struct pt_regs regs)
 {
         unsigned long clone_flags;
         unsigned long newsp;
@@ -308,7 +310,7 @@
  * do not have enough call-clobbered registers to hold all
  * the information you need.
  */
-asmlinkage int sys_vfork(struct pt_regs regs)
+asmlinkage long sys_vfork(struct pt_regs regs)
 {
 	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
 		       regs.gprs[15], &regs, 0, NULL, NULL);
@@ -317,7 +319,7 @@
 /*
  * sys_execve() executes a new program.
  */
-asmlinkage int sys_execve(struct pt_regs regs)
+asmlinkage long sys_execve(struct pt_regs regs)
 {
         int error;
         char * filename;
diff -Nru a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
--- a/arch/s390/kernel/ptrace.c	Sat Apr  3 19:38:55 2004
+++ b/arch/s390/kernel/ptrace.c	Sat Apr  3 19:38:55 2004
@@ -137,25 +137,36 @@
 	if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
 		return -EIO;
 
-	if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
+	if (addr < (addr_t) &dummy->regs.acrs) {
 		/*
-		 * psw, gprs, acrs and orig_gpr2 are stored on the stack
+		 * psw and gprs are stored on the stack
 		 */
 		tmp = *(addr_t *)((addr_t) __KSTK_PTREGS(child) + addr);
 		if (addr == (addr_t) &dummy->regs.psw.mask)
 			/* Remove per bit from user psw. */
 			tmp &= ~PSW_MASK_PER;
 
-	} else if (addr >= (addr_t) &dummy->regs.fp_regs &&
-		   addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
+	} else if (addr < (addr_t) &dummy->regs.orig_gpr2) {
+		/*
+		 * access registers are stored in the thread structure
+		 */
+		offset = addr - (addr_t) &dummy->regs.acrs;
+		tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
+
+	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
+		/*
+		 * orig_gpr2 is stored on the kernel stack
+		 */
+		tmp = (addr_t) __KSTK_PTREGS(child)->orig_gpr2;
+
+	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
 		/* 
 		 * floating point regs. are stored in the thread structure
 		 */
 		offset = addr - (addr_t) &dummy->regs.fp_regs;
 		tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
 
-	} else if (addr >= (addr_t) &dummy->regs.per_info &&
-		   addr < (addr_t) (&dummy->regs.per_info + 1)) {
+	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
 		/*
 		 * per_info is found in the thread structure
 		 */
@@ -187,15 +198,15 @@
 	if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK)
 		return -EIO;
 
-	if (addr <= (addr_t) &dummy->regs.orig_gpr2) {
+	if (addr < (addr_t) &dummy->regs.acrs) {
 		/*
-		 * psw, gprs, acrs and orig_gpr2 are stored on the stack
+		 * psw and gprs are stored on the stack
 		 */
 		if (addr == (addr_t) &dummy->regs.psw.mask &&
 #ifdef CONFIG_S390_SUPPORT
-		    (data & ~PSW_MASK_CC) != PSW_USER32_BITS &&
+		    data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
 #endif
-		    (data & ~PSW_MASK_CC) != PSW_USER_BITS)
+		    data != PSW_MASK_MERGE(PSW_USER_BITS, data))
 			/* Invalid psw mask. */
 			return -EINVAL;
 #ifndef CONFIG_ARCH_S390X
@@ -206,8 +217,20 @@
 #endif
 		*(addr_t *)((addr_t) __KSTK_PTREGS(child) + addr) = data;
 
-	} else if (addr >= (addr_t) &dummy->regs.fp_regs &&
-		   addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
+	} else if (addr < (addr_t) (&dummy->regs.orig_gpr2)) {
+		/*
+		 * access registers are stored in the thread structure
+		 */
+		offset = addr - (addr_t) &dummy->regs.acrs;
+		*(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
+
+	} else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
+		/*
+		 * orig_gpr2 is stored on the kernel stack
+		 */
+		__KSTK_PTREGS(child)->orig_gpr2 = data;
+
+	} else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) {
 		/*
 		 * floating point regs. are stored in the thread structure
 		 */
@@ -217,8 +240,7 @@
 		offset = addr - (addr_t) &dummy->regs.fp_regs;
 		*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
 
-	} else if (addr >= (addr_t) &dummy->regs.per_info &&
-		   addr < (addr_t) (&dummy->regs.per_info + 1)) {
+	} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
 		/*
 		 * per_info is found in the thread structure 
 		 */
@@ -324,40 +346,44 @@
 	    (addr & 3) || addr > sizeof(struct user) - 3)
 		return -EIO;
 
-	if (addr <= (addr_t) &dummy32->regs.orig_gpr2) {
+	if (addr < (addr_t) &dummy32->regs.acrs) {
 		/*
-		 * psw, gprs, acrs and orig_gpr2 are stored on the stack
+		 * psw and gprs are stored on the stack
 		 */
 		if (addr == (addr_t) &dummy32->regs.psw.mask) {
 			/* Fake a 31 bit psw mask. */
 			tmp = (__u32)(__KSTK_PTREGS(child)->psw.mask >> 32);
-			tmp = (tmp & PSW32_MASK_CC) | PSW32_USER_BITS;
+			tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp);
 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
 			/* Fake a 31 bit psw address. */
 			tmp = (__u32) __KSTK_PTREGS(child)->psw.addr |
 				PSW32_ADDR_AMODE31;
-		} else if (addr < (addr_t) &dummy32->regs.acrs[0]) {
+		} else {
 			/* gpr 0-15 */
 			tmp = *(__u32 *)((addr_t) __KSTK_PTREGS(child) + 
 					 addr*2 + 4);
-		} else if (addr < (addr_t) &dummy32->regs.orig_gpr2) {
-			offset = PT_ACR0 + addr - (addr_t) &dummy32->regs.acrs;
-			tmp = *(__u32*)((addr_t) __KSTK_PTREGS(child) + offset);
-		} else {
-			/* orig gpr 2 */
-			offset = PT_ORIGGPR2 + 4;
-			tmp = *(__u32*)((addr_t) __KSTK_PTREGS(child) + offset);
 		}
-	} else if (addr >= (addr_t) &dummy32->regs.fp_regs &&
-		   addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
+	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
+		/*
+		 * access registers are stored in the thread structure
+		 */
+		offset = addr - (addr_t) &dummy32->regs.acrs;
+		tmp = *(__u32*)((addr_t) &child->thread.acrs + offset);
+
+	} else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) {
+		/*
+		 * orig_gpr2 is stored on the kernel stack
+		 */
+		tmp = *(__u32*)((addr_t) &__KSTK_PTREGS(child)->orig_gpr2 + 4);
+
+	} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
 		/*
 		 * floating point regs. are stored in the thread structure 
 		 */
 	        offset = addr - (addr_t) &dummy32->regs.fp_regs;
 		tmp = *(__u32 *)((addr_t) &child->thread.fp_regs + offset);
 
-	} else if (addr >= (addr_t) &dummy32->regs.per_info &&
-		   addr < (addr_t) (&dummy32->regs.per_info + 1)) {
+	} else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
 		/*
 		 * per_info is found in the thread structure
 		 */
@@ -396,34 +422,40 @@
 
 	tmp = (__u32) data;
 
-	if (addr <= (addr_t) &dummy32->regs.orig_gpr2) {
+	if (addr < (addr_t) &dummy32->regs.acrs) {
 		/*
 		 * psw, gprs, acrs and orig_gpr2 are stored on the stack
 		 */
 		if (addr == (addr_t) &dummy32->regs.psw.mask) {
 			/* Build a 64 bit psw mask from 31 bit mask. */
-			if ((tmp & ~PSW32_MASK_CC) != PSW32_USER_BITS)
+			if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp))
 				/* Invalid psw mask. */
 				return -EINVAL;
-			__KSTK_PTREGS(child)->psw.mask = PSW_USER32_BITS |
-				((tmp & PSW32_MASK_CC) << 32);
+			__KSTK_PTREGS(child)->psw.mask =
+				PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32);
 		} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
 			/* Build a 64 bit psw address from 31 bit address. */
 			__KSTK_PTREGS(child)->psw.addr = 
 				(__u64) tmp & PSW32_ADDR_INSN;
-		} else if (addr < (addr_t) &dummy32->regs.acrs[0]) {
+		} else {
 			/* gpr 0-15 */
 			*(__u32*)((addr_t) __KSTK_PTREGS(child) + addr*2 + 4) =
 				tmp;
-		} else if (addr < (addr_t) &dummy32->regs.orig_gpr2) {
-			offset = PT_ACR0 + addr - (addr_t) &dummy32->regs.acrs;
-			*(__u32*)((addr_t) __KSTK_PTREGS(child) + offset) = tmp;
-		} else {
-			offset = PT_ORIGGPR2 + 4;
-			*(__u32*)((addr_t) __KSTK_PTREGS(child) + offset) = tmp;
 		}
-	} else if (addr >= (addr_t) &dummy32->regs.fp_regs &&
-		   addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
+	} else if (addr < (addr_t) (&dummy32->regs.orig_gpr2)) {
+		/*
+		 * access registers are stored in the thread structure
+		 */
+		offset = addr - (addr_t) &dummy32->regs.acrs;
+		*(__u32*)((addr_t) &child->thread.acrs + offset) = tmp;
+
+	} else if (addr == (addr_t) (&dummy32->regs.orig_gpr2)) {
+		/*
+		 * orig_gpr2 is stored on the kernel stack
+		 */
+		*(__u32*)((addr_t) &__KSTK_PTREGS(child)->orig_gpr2 + 4) = tmp;
+
+	} else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) {
 		/*
 		 * floating point regs. are stored in the thread structure 
 		 */
@@ -434,8 +466,7 @@
 	        offset = addr - (addr_t) &dummy32->regs.fp_regs;
 		*(__u32 *)((addr_t) &child->thread.fp_regs + offset) = tmp;
 
-	} else if (addr >= (addr_t) &dummy32->regs.per_info &&
-		   addr < (addr_t) (&dummy32->regs.per_info + 1)) {
+	} else if (addr < (addr_t) (&dummy32->regs.per_info + 1)) {
 		/*
 		 * per_info is found in the thread structure.
 		 */
@@ -616,7 +647,7 @@
 	return -EIO;
 }
 
-asmlinkage int
+asmlinkage long
 sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
diff -Nru a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
--- a/arch/s390/kernel/s390_ksyms.c	Sat Apr  3 19:38:44 2004
+++ b/arch/s390/kernel/s390_ksyms.c	Sat Apr  3 19:38:44 2004
@@ -33,6 +33,8 @@
 EXPORT_SYMBOL_NOVERS(__copy_from_user_asm);
 EXPORT_SYMBOL_NOVERS(__copy_to_user_asm);
 EXPORT_SYMBOL_NOVERS(__clear_user_asm);
+EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm);
+EXPORT_SYMBOL_NOVERS(__strnlen_user_asm);
 EXPORT_SYMBOL(diag10);
 
 /*
diff -Nru a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
--- a/arch/s390/kernel/setup.c	Sat Apr  3 19:38:41 2004
+++ b/arch/s390/kernel/setup.c	Sat Apr  3 19:38:41 2004
@@ -492,26 +492,27 @@
 #endif /* CONFIG_ARCH_S390X */
 	lc->restart_psw.mask = PSW_BASE_BITS;
 	lc->restart_psw.addr =
-		PSW_ADDR_AMODE + (unsigned long) restart_int_handler;
+		PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
 	lc->external_new_psw.mask = PSW_KERNEL_BITS;
 	lc->external_new_psw.addr =
-		PSW_ADDR_AMODE + (unsigned long) ext_int_handler;
-	lc->svc_new_psw.mask = PSW_KERNEL_BITS;
-	lc->svc_new_psw.addr = PSW_ADDR_AMODE + (unsigned long) system_call;
+		PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
+	lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+	lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
 	lc->program_new_psw.mask = PSW_KERNEL_BITS;
 	lc->program_new_psw.addr =
-		PSW_ADDR_AMODE + (unsigned long)pgm_check_handler;
+		PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
 	lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
 	lc->mcck_new_psw.addr =
-		PSW_ADDR_AMODE + (unsigned long) mcck_int_handler;
+		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
 	lc->io_new_psw.mask = PSW_KERNEL_BITS;
-	lc->io_new_psw.addr = PSW_ADDR_AMODE + (unsigned long) io_int_handler;
+	lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
 	lc->ipl_device = S390_lowcore.ipl_device;
 	lc->jiffy_timer = -1LL;
 	lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
 	lc->async_stack = (unsigned long)
 		__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
 	lc->current_task = (unsigned long) init_thread_union.thread_info.task;
+	lc->thread_info = (unsigned long) &init_thread_union;
 #ifdef CONFIG_ARCH_S390X
 	if (MACHINE_HAS_DIAG44)
 		lc->diag44_opcode = 0x83000044;
diff -Nru a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
--- a/arch/s390/kernel/signal.c	Sat Apr  3 19:38:55 2004
+++ b/arch/s390/kernel/signal.c	Sat Apr  3 19:38:55 2004
@@ -148,9 +148,21 @@
 /* Returns non-zero on fault. */
 static int save_sigregs(struct pt_regs *regs, _sigregs *sregs)
 {
+	unsigned long old_mask = regs->psw.mask;
 	int err;
   
-	err = __copy_to_user(&sregs->regs, regs, sizeof(_s390_regs_common));
+	save_access_regs(current->thread.acrs);
+
+	/* Copy a 'clean' PSW mask to the user to avoid leaking
+	   information about whether PER is currently on.  */
+	regs->psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
+	err = __copy_to_user(&sregs->regs.psw, &regs->psw,
+			     sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs));
+	regs->psw.mask = old_mask;
+	if (err != 0)
+		return err;
+	err = __copy_to_user(&sregs->regs.acrs, current->thread.acrs,
+			     sizeof(sregs->regs.acrs));
 	if (err != 0)
 		return err;
 	/* 
@@ -165,16 +177,23 @@
 /* Returns positive number on error */
 static int restore_sigregs(struct pt_regs *regs, _sigregs *sregs)
 {
+	unsigned long old_mask = regs->psw.mask;
 	int err;
 
 	/* Alwys make any pending restarted system call return -EINTR */
 	current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-	err = __copy_from_user(regs, &sregs->regs, sizeof(_s390_regs_common));
-	regs->psw.mask = PSW_USER_BITS | (regs->psw.mask & PSW_MASK_CC);
+	err = __copy_from_user(&regs->psw, &sregs->regs.psw,
+			       sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs));
+	regs->psw.mask = PSW_MASK_MERGE(old_mask, regs->psw.mask);
 	regs->psw.addr |= PSW_ADDR_AMODE;
 	if (err)
 		return err;
+	err = __copy_from_user(&current->thread.acrs, &sregs->regs.acrs,
+			       sizeof(sregs->regs.acrs));
+	if (err)
+		return err;
+	restore_access_regs(current->thread.acrs);
 
 	err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
 			       sizeof(s390_fp_regs));
@@ -319,7 +338,6 @@
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (unsigned long) frame;
 	regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
-	regs->psw.mask = PSW_USER_BITS;
 
 	regs->gprs[2] = map_signal(sig);
 	regs->gprs[3] = (unsigned long) &frame->sc;
@@ -378,7 +396,6 @@
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (unsigned long) frame;
 	regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
-	regs->psw.mask = PSW_USER_BITS;
 
 	regs->gprs[2] = map_signal(sig);
 	regs->gprs[3] = (unsigned long) &frame->info;
@@ -401,30 +418,6 @@
 {
 	struct k_sigaction *ka = &current->sighand->action[sig-1];
 
-	/* Are we from a system call? */
-	if (regs->trap == __LC_SVC_OLD_PSW) {
-		/* If so, check system call restarting.. */
-		switch (regs->gprs[2]) {
-			case -ERESTART_RESTARTBLOCK:
-				current_thread_info()->restart_block.fn =
-					do_no_restart_syscall;
-				clear_thread_flag(TIF_RESTART_SVC);
-			case -ERESTARTNOHAND:
-				regs->gprs[2] = -EINTR;
-				break;
-
-			case -ERESTARTSYS:
-				if (!(ka->sa.sa_flags & SA_RESTART)) {
-					regs->gprs[2] = -EINTR;
-					break;
-				}
-			/* fallthrough */
-			case -ERESTARTNOINTR:
-				regs->gprs[2] = regs->orig_gpr2;
-				regs->psw.addr -= regs->ilc;
-		}
-	}
-
 	/* Set up the stack frame */
 	if (ka->sa.sa_flags & SA_SIGINFO)
 		setup_rt_frame(sig, ka, info, oldset, regs);
@@ -454,6 +447,7 @@
  */
 int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
+	unsigned long retval = 0, continue_addr = 0, restart_addr = 0;
 	siginfo_t info;
 	int signr;
 
@@ -468,35 +462,62 @@
 
 	if (!oldset)
 		oldset = &current->blocked;
-#ifdef CONFIG_S390_SUPPORT 
-	if (test_thread_flag(TIF_31BIT)) {
-		extern asmlinkage int do_signal32(struct pt_regs *regs,
-						  sigset_t *oldset); 
-		return do_signal32(regs, oldset);
-        }
-#endif 
 
+	/* Are we from a system call? */
+	if (regs->trap == __LC_SVC_OLD_PSW) {
+		continue_addr = regs->psw.addr;
+		restart_addr = continue_addr - regs->ilc;
+		retval = regs->gprs[2];
+
+		/* Prepare for system call restart.  We do this here so that a
+		   debugger will see the already changed PSW. */
+		if (retval == -ERESTARTNOHAND ||
+		    retval == -ERESTARTSYS ||
+		    retval == -ERESTARTNOINTR) {
+			regs->gprs[2] = regs->orig_gpr2;
+			regs->psw.addr = restart_addr;
+		} else if (retval == -ERESTART_RESTARTBLOCK) {
+			regs->gprs[2] = -EINTR;
+		}
+	}
+
+	/* Get signal to deliver.  When running under ptrace, at this point
+	   the debugger may change all our registers ... */
 	signr = get_signal_to_deliver(&info, regs, NULL);
+
+	/* Depending on the signal settings we may need to revert the
+	   decision to restart the system call. */
+	if (signr > 0 && regs->psw.addr == restart_addr) {
+		if (retval == -ERESTARTNOHAND
+		    || (retval == -ERESTARTSYS
+			 && !(current->sighand->action[signr-1].sa.sa_flags
+			      & SA_RESTART))) {
+			regs->gprs[2] = -EINTR;
+			regs->psw.addr = continue_addr;
+		}
+	}
+
 	if (signr > 0) {
 		/* Whee!  Actually deliver the signal.  */
+#ifdef CONFIG_S390_SUPPORT
+		if (test_thread_flag(TIF_31BIT)) {
+			extern void handle_signal32(unsigned long sig,
+						    siginfo_t *info,
+						    sigset_t *oldset,
+						    struct pt_regs *regs);
+			handle_signal32(signr, &info, oldset, regs);
+			return 1;
+	        }
+#endif
 		handle_signal(signr, &info, oldset, regs);
 		return 1;
 	}
 
-	/* Did we come from a system call? */
-	if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) {
-		/* Restart the system call - no handlers present */
-		if (regs->gprs[2] == -ERESTARTNOHAND ||
-		    regs->gprs[2] == -ERESTARTSYS ||
-		    regs->gprs[2] == -ERESTARTNOINTR) {
-			regs->gprs[2] = regs->orig_gpr2;
-			regs->psw.addr -= regs->ilc;
-		}
-		/* Restart the system call with a new system call number */
-		if (regs->gprs[2] == -ERESTART_RESTARTBLOCK) {
-			regs->gprs[2] = __NR_restart_syscall;
-			set_thread_flag(TIF_RESTART_SVC);
-		}
+	/* Restart a different system call. */
+	if (retval == -ERESTART_RESTARTBLOCK
+	    && regs->psw.addr == continue_addr) {
+		regs->gprs[2] = __NR_restart_syscall;
+		set_thread_flag(TIF_RESTART_SVC);
 	}
 	return 0;
 }
diff -Nru a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
--- a/arch/s390/kernel/sys_s390.c	Sat Apr  3 19:38:42 2004
+++ b/arch/s390/kernel/sys_s390.c	Sat Apr  3 19:38:42 2004
@@ -32,17 +32,11 @@
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 
-#ifndef CONFIG_ARCH_S390X
-#define __SYS_RETTYPE int
-#else
-#define __SYS_RETTYPE long
-#endif /* CONFIG_ARCH_S390X */
-
 /*
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way Unix traditionally does this, though.
  */
-asmlinkage __SYS_RETTYPE sys_pipe(unsigned long * fildes)
+asmlinkage long sys_pipe(unsigned long * fildes)
 {
 	int fd[2];
 	int error;
@@ -61,7 +55,7 @@
 	unsigned long prot, unsigned long flags,
 	unsigned long fd, unsigned long pgoff)
 {
-	__SYS_RETTYPE error = -EBADF;
+	long error = -EBADF;
 	struct file * file = NULL;
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
@@ -109,10 +103,10 @@
 	return error;
 }
 
-asmlinkage __SYS_RETTYPE old_mmap(struct mmap_arg_struct *arg)
+asmlinkage long old_mmap(struct mmap_arg_struct *arg)
 {
 	struct mmap_arg_struct a;
-	__SYS_RETTYPE error = -EFAULT;
+	long error = -EFAULT;
 
 	if (copy_from_user(&a, arg, sizeof(a)))
 		goto out;
@@ -133,7 +127,7 @@
 	struct timeval *tvp;
 };
 
-asmlinkage int old_select(struct sel_arg_struct *arg)
+asmlinkage long old_select(struct sel_arg_struct *arg)
 {
 	struct sel_arg_struct a;
 
@@ -182,7 +176,7 @@
  *
  * This is really horribly ugly.
  */
-asmlinkage __SYS_RETTYPE sys_ipc (uint call, int first, int second, 
+asmlinkage long sys_ipc (uint call, int first, int second,
 				  unsigned long third, void *ptr)
 {
         struct ipc_kludge tmp;
@@ -245,58 +239,8 @@
 	return -EINVAL;
 }
 
-/*
- * Old cruft
- */
-asmlinkage int sys_uname(struct old_utsname * name)
-{
-	int err;
-	if (!name)
-		return -EFAULT;
-	down_read(&uts_sem);
-	err=copy_to_user(name, &system_utsname, sizeof (*name));
-	up_read(&uts_sem);
-	return err?-EFAULT:0;
-}
-
-#ifndef CONFIG_ARCH_S390X
-asmlinkage int sys_olduname(struct oldold_utsname * name)
-{
-	int error;
-
-	if (!name)
-		return -EFAULT;
-	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
-		return -EFAULT;
-  
-  	down_read(&uts_sem);
-	
-	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
-	error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
-	error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
-	error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
-	error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
-	error |= __put_user(0,name->release+__OLD_UTS_LEN);
-	error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
-	error |= __put_user(0,name->version+__OLD_UTS_LEN);
-	error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
-	error |= __put_user(0,name->machine+__OLD_UTS_LEN);
-	
-	up_read(&uts_sem);
-	
-	error = error ? -EFAULT : 0;
-
-	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)
+#ifdef CONFIG_ARCH_S390X
+asmlinkage long s390x_newuname(struct new_utsname * name)
 {
 	int ret = sys_newuname(name);
 
@@ -307,7 +251,7 @@
 	return ret;
 }
 
-asmlinkage int s390x_personality(unsigned long personality)
+asmlinkage long s390x_personality(unsigned long personality)
 {
 	int ret;
 
diff -Nru a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
--- a/arch/s390/kernel/syscalls.S	Sat Apr  3 19:38:41 2004
+++ b/arch/s390/kernel/syscalls.S	Sat Apr  3 19:38:41 2004
@@ -54,7 +54,7 @@
 SYSCALL(sys_times,sys_times,compat_sys_times_wrapper)
 NI_SYSCALL							/* old prof syscall */
 SYSCALL(sys_brk,sys_brk,sys32_brk_wrapper)			/* 45 */
-SYSCALL(sys_setgid16,sys_ni_syscall,sys32_setgid16)		/* old setgid16 syscall*/
+SYSCALL(sys_setgid16,sys_ni_syscall,sys32_setgid16_wrapper)	/* old setgid16 syscall*/
 SYSCALL(sys_getgid16,sys_ni_syscall,sys32_getgid16)		/* old getgid16 syscall*/
 SYSCALL(sys_signal,sys_signal,sys32_signal_wrapper)
 SYSCALL(sys_geteuid16,sys_ni_syscall,sys32_geteuid16)		/* old geteuid16 syscall */
@@ -109,7 +109,7 @@
 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,5 @@
 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_statfs64,sys_statfs64,compat_sys_statfs64_wrapper)
+SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper)
diff -Nru a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
--- a/arch/s390/kernel/traps.c	Sat Apr  3 19:38:42 2004
+++ b/arch/s390/kernel/traps.c	Sat Apr  3 19:38:42 2004
@@ -173,6 +173,10 @@
 	printk("           " FOURLONG,
 	       regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
 
+#if 0
+	/* FIXME: this isn't needed any more but it changes the ksymoops
+	 * input. To remove or not to remove ... */
+	save_access_regs(regs->acrs);
 	printk("%s ACRS: %08x %08x %08x %08x\n", mode,
 	       regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]);
 	printk("           %08x %08x %08x %08x\n",
@@ -181,6 +185,7 @@
 	       regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]);
 	printk("           %08x %08x %08x %08x\n",
 	       regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]);
+#endif
 
 	/*
 	 * Print the first 20 byte of the instruction stream at the
@@ -229,17 +234,17 @@
 			  regs->gprs[12], regs->gprs[13],
 			  regs->gprs[14], regs->gprs[15]);
 	buffer += sprintf(buffer, "User ACRS: %08x %08x %08x %08x\n",
-			  regs->acrs[0], regs->acrs[1],
-			  regs->acrs[2], regs->acrs[3]);
+			  task->thread.acrs[0], task->thread.acrs[1],
+			  task->thread.acrs[2], task->thread.acrs[3]);
 	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
-			  regs->acrs[4], regs->acrs[5],
-			  regs->acrs[6], regs->acrs[7]);
+			  task->thread.acrs[4], task->thread.acrs[5],
+			  task->thread.acrs[6], task->thread.acrs[7]);
 	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
-			  regs->acrs[8], regs->acrs[9],
-			  regs->acrs[10], regs->acrs[11]);
+			  task->thread.acrs[8], task->thread.acrs[9],
+			  task->thread.acrs[10], task->thread.acrs[11]);
 	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
-			  regs->acrs[12], regs->acrs[13],
-			  regs->acrs[14], regs->acrs[15]);
+			  task->thread.acrs[12], task->thread.acrs[13],
+			  task->thread.acrs[14], task->thread.acrs[15]);
 	return buffer;
 }
 
@@ -308,7 +313,7 @@
 	return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
 }
 
-static int do_debugger_trap(struct pt_regs *regs)
+int do_debugger_trap(struct pt_regs *regs)
 {
 	if ((regs->psw.mask & PSW_MASK_PSTATE) &&
 	    (current->ptrace & PT_PTRACED)) {
@@ -652,23 +657,3 @@
 #endif
 	}
 }
-
-
-void handle_per_exception(struct pt_regs *regs)
-{
-	if (regs->psw.mask & PSW_MASK_PSTATE) {
-		per_struct *per_info=&current->thread.per_info;
-		per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
-		per_info->lowcore.words.address=S390_lowcore.per_address;
-		per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
-	}
-	if (do_debugger_trap(regs)) {
-		/* I've seen this possibly a task structure being reused ? */
-		printk("Spurious per exception detected\n");
-		printk("switching off per tracing for this task.\n");
-		show_regs(regs);
-		/* Hopefully switching off per tracing will help us survive */
-		regs->psw.mask &= ~PSW_MASK_PER;
-	}
-}
-
diff -Nru a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S
--- a/arch/s390/lib/uaccess.S	Sat Apr  3 19:38:45 2004
+++ b/arch/s390/lib/uaccess.S	Sat Apr  3 19:38:45 2004
@@ -9,135 +9,191 @@
  *  These functions have standard call interface
  */
 
+#include <linux/errno.h>
 #include <asm/lowcore.h>
+#include <asm/offsets.h>
 
         .text
         .align 4
         .globl __copy_from_user_asm
+	# %r2 = to, %r3 = n, %r4 = from
 __copy_from_user_asm:
-	lr	%r5,%r3
-	sacf	512
-0:	mvcle	%r2,%r4,0
-	jo	0b
-1:	sacf	0
-	lr	%r2,%r5
-	br	%r14
-2:	lhi	%r1,-4096
-	lr	%r3,%r4
-	slr	%r3,%r1      # %r3 = %r4 + 4096
-	nr	%r3,%r1      # %r3 = (%r4 + 4096) & -4096
-	slr	%r3,%r4      # %r3 = #bytes to next user page boundary
-	clr	%r5,%r3      # copy crosses next page boundary ?
-	jnh	1b           # no, this page fauled
-	# The page after the current user page might have faulted.
-	# We cant't find out which page because the program check handler
-	# might have callled schedule, destroying all lowcore information.
-	# We retry with the shortened length.
-3:	mvcle	%r2,%r4,0
-	jo	3b
-	j	1b
+	slr	%r0,%r0
+0:	mvcp	0(%r3,%r2),0(%r4),%r0
+	jnz	1f
+	slr	%r2,%r2
+	br	%r14
+1:	la	%r2,256(%r2)
+	la	%r4,256(%r4)
+	ahi	%r3,-256
+2:	mvcp	0(%r3,%r2),0(%r4),%r0
+	jnz	1b
+3:	slr	%r2,%r2
+	br	%r14
+4:	lhi	%r0,-4096
+	lr	%r5,%r4
+	slr	%r5,%r0
+	nr	%r5,%r0		# %r5 = (%r4 + 4096) & -4096
+	slr	%r5,%r4		# %r5 = #bytes to next user page boundary
+	clr	%r3,%r5		# copy crosses next page boundary ?
+	jnh	6f		# no, the current page faulted
+	# move with the reduced length which is < 256
+5:	mvcp	0(%r5,%r2),0(%r4),%r0
+	slr	%r3,%r5
+6:	lr	%r2,%r3
+	br	%r14
         .section __ex_table,"a"
-	.long	0b,2b
-	.long	3b,1b
+	.long	0b,4b
+	.long	2b,4b
+	.long	5b,6b
         .previous
 
         .align 4
         .text
         .globl __copy_to_user_asm
+	# %r2 = from, %r3 = n, %r4 = to
 __copy_to_user_asm:
-	lr	%r5,%r3
-	sacf	512
-0:	mvcle	%r4,%r2,0
-	jo	0b
-1:	sacf	0
-	lr	%r2,%r3
+	slr	%r0,%r0
+0:	mvcs	0(%r3,%r4),0(%r2),%r0
+	jnz	1f
+	slr	%r2,%r2
+	br	%r14
+1:	la	%r2,256(%r2)
+	la	%r4,256(%r4)
+	ahi	%r3,-256
+2:	mvcs	0(%r3,%r4),0(%r2),%r0
+	jnz	1b
+3:	slr	%r2,%r2
 	br	%r14
-2:	lhi	%r1,-4096
+4:	lhi	%r0,-4096
 	lr	%r5,%r4
-	slr	%r5,%r1      # %r5 = %r4 + 4096
-	nr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
-	slr	%r5,%r4      # %r5 = #bytes to next user page boundary
-	clr	%r3,%r5      # copy crosses next page boundary ?
-	jnh	1b           # no, the current page fauled
-	# The page after the current user page might have faulted.
-	# We cant't find out which page because the program check handler
-	# might have callled schedule, destroying all lowcore information.
-	# We retry with the shortened length.
-3:	mvcle	%r4,%r2,0
-	jo	3b
-	j	1b
+	slr	%r5,%r0
+	nr	%r5,%r0		# %r5 = (%r4 + 4096) & -4096
+	slr	%r5,%r4		# %r5 = #bytes to next user page boundary
+	clr	%r3,%r5		# copy crosses next page boundary ?
+	jnh	6f		# no, the current page faulted
+	# move with the reduced length which is < 256
+5:	mvcs	0(%r5,%r4),0(%r2),%r0
+	slr	%r3,%r5
+6:	lr	%r2,%r3
+	br	%r14
         .section __ex_table,"a"
-	.long	0b,2b
-	.long	3b,1b
+	.long	0b,4b
+	.long	2b,4b
+	.long	5b,6b
         .previous
 
         .align 4
         .text
         .globl __copy_in_user_asm
+	# %r2 = from, %r3 = n, %r4 = to
 __copy_in_user_asm:
-	stm	%r6,%r15,24(%r15)
-	lr	%r5,%r3
-	lr	%r7,%r3
-	lr	%r6,%r2
-	cpya	6,4          # ar6 = ar4
-	sacf	512
-0:	mvcle	%r4,%r6,0
-	jo	0b
-1:	sacf	0
-	lr	%r2,%r7
-	lm	%r6,%r15,24(%r15)
+	sacf	256
+	bras	1,1f
+	mvc	0(1,%r4),0(%r2)
+0:	mvc	0(256,%r4),0(%r2)
+	la	%r2,256(%r2)
+	la	%r4,256(%r4)
+1:	ahi	%r3,-256
+	jnm	0b
+2:	ex	%r3,0(%r1)
+	sacf	0
+	slr	%r2,%r2
+	br	14
+3:	mvc	0(1,%r4),0(%r2)
+	la	%r2,1(%r2)
+	la	%r4,1(%r4)
+	ahi	%r3,-1
+	jnm	3b
+4:	lr	%r2,%r3
+	sacf	0
 	br	%r14
-2:	lhi	%r1,-4096
-	lr	%r5,%r4
-	slr	%r5,%r1      # %r5 = %r4 + 4096
-	nr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
-	slr	%r5,%r4      # %r5 = #bytes to next user page boundary
-	clr	%r7,%r5      # copy crosses next page boundary ?
-	jnh	1b           # no, the current page fauled
-	# The page after the current user page might have faulted.
-	# We cant't find out which page because the program check handler
-	# might have callled schedule, destroying all lowcore information.
-	# We retry with the shortened length.
-3:	mvcle	%r4,%r6,0
-	jo	3b
-	j	1b
         .section __ex_table,"a"
-	.long	0b,2b
-	.long	3b,1b
+	.long	0b,3b
+	.long	2b,3b
+	.long	3b,4b
         .previous
 
         .align 4
         .text
         .globl __clear_user_asm
+	# %r2 = to, %r3 = n
 __clear_user_asm:
+	bras	%r5,0f
+	.long	empty_zero_page
+0:	l	%r5,0(%r5)
+	slr	%r0,%r0
+1:	mvcs	0(%r3,%r2),0(%r5),%r0
+	jnz	2f
+	slr	%r2,%r2
+	br	%r14
+2:	la	%r2,256(%r2)
+	ahi	%r3,-256
+3:	mvcs	0(%r3,%r2),0(%r5),%r0
+	jnz	2b
+4:	slr	%r2,%r2
+	br	%r14
+5:	lhi	%r0,-4096
 	lr	%r4,%r2
-	lr	%r5,%r3
-	sr	%r2,%r2
-	sr	%r3,%r3
-	sacf	512
-0:	mvcle	%r4,%r2,0
-	jo	0b
-1:	sacf	0
-	br	%r14
-2:	lr	%r2,%r5
-	lhi	%r1,-4096
-	slr	%r5,%r1      # %r5 = %r4 + 4096
-	nr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
-	slr	%r5,%r4      # %r5 = #bytes to next user page boundary
-	clr	%r2,%r5      # copy crosses next page boundary ?
-	jnh	1b           # no, the current page fauled
-	# The page after the current user page might have faulted.
-	# We cant't find out which page because the program check handler
-	# might have callled schedule, destroying all lowcore information.
-	# We retry with the shortened length.
-	slr	%r2,%r5
-3:	mvcle	%r4,%r2,0
-	jo	3b
-	j	1b
-4:	alr	%r2,%r5
-	j	1b
+	slr	%r4,%r0
+	nr	%r4,%r0		# %r4 = (%r2 + 4096) & -4096
+	slr	%r4,%r2		# %r4 = #bytes to next user page boundary
+	clr	%r3,%r4		# clear crosses next page boundary ?
+	jnh	7f		# no, the current page faulted
+	# clear with the reduced length which is < 256
+6:	mvcs	0(%r4,%r2),0(%r5),%r0
+	slr	%r3,%r4
+7:	lr	%r2,%r3
+	br	%r14
         .section __ex_table,"a"
-	.long	0b,2b
-        .long	3b,4b
+	.long	1b,5b
+	.long	3b,5b
+	.long	6b,7b
         .previous
 
+        .align 4
+        .text
+        .globl __strncpy_from_user_asm
+	# %r2 = dst, %r3 = src, %r4 = count
+__strncpy_from_user_asm:
+	lhi	%r0,0
+	lhi	%r1,1
+	lhi	%r5,0
+0:	mvcp	0(%r1,%r2),0(%r3),%r0
+	tm	0(%r2),0xff
+	jz	1f
+	la	%r2,1(%r2)
+	la	%r3,1(%r3)
+	ahi	%r5,1
+	clr	%r5,%r4
+	jl	0b
+1:	lr	%r2,%r5
+	br	%r14
+2:	lhi	%r2,-EFAULT
+	br	%r14
+        .section __ex_table,"a"
+	.long	0b,2b
+	.previous
+
+        .align 4
+        .text
+        .globl __strnlen_user_asm
+	# %r2 = src, %r3 = count
+__strnlen_user_asm:
+	lhi	%r0,0
+	lhi	%r1,1
+	lhi	%r5,0
+0:	mvcp	24(%r1,%r15),0(%r2),%r0
+	ahi	%r5,1
+	tm	24(%r15),0xff
+	jz	1f
+	la	%r2,1(%r2)
+	clr	%r5,%r3
+	jl	0b
+1:	lr	%r2,%r5
+	br	%r14
+2:	lhi	%r2,-EFAULT
+	br	%r14
+        .section __ex_table,"a"
+	.long	0b,2b
+	.previous
diff -Nru a/arch/s390/lib/uaccess64.S b/arch/s390/lib/uaccess64.S
--- a/arch/s390/lib/uaccess64.S	Sat Apr  3 19:38:55 2004
+++ b/arch/s390/lib/uaccess64.S	Sat Apr  3 19:38:55 2004
@@ -9,134 +9,189 @@
  *  These functions have standard call interface
  */
 
+#include <linux/errno.h>
 #include <asm/lowcore.h>
+#include <asm/offsets.h>
 
         .text
         .align 4
         .globl __copy_from_user_asm
+	# %r2 = to, %r3 = n, %r4 = from
 __copy_from_user_asm:
-	lgr	%r5,%r3
-	sacf	512
-0:	mvcle	%r2,%r4,0
-	jo	0b
-1:	sacf	0
-	lgr	%r2,%r5
-	br	%r14
-2:	lghi	%r1,-4096
-	lgr	%r3,%r4
-	slgr	%r3,%r1      # %r3 = %r4 + 4096
-	ngr	%r3,%r1      # %r3 = (%r4 + 4096) & -4096
-	slgr	%r3,%r4      # %r3 = #bytes to next user page boundary
-	clgr	%r5,%r3      # copy crosses next page boundary ?
-	jnh	1b           # no, this page fauled
-	# The page after the current user page might have faulted.
-	# We cant't find out which page because the program check handler
-	# might have callled schedule, destroying all lowcore information.
-	# We retry with the shortened length.
-3:	mvcle	%r2,%r4,0
-	jo	3b
-	j	1b
+	slgr	%r0,%r0
+0:	mvcp	0(%r3,%r2),0(%r4),%r0
+	jnz	1f
+	slgr	%r2,%r2
+	br	%r14
+1:	la	%r2,256(%r2)
+	la	%r4,256(%r4)
+	aghi	%r3,-256
+2:	mvcp	0(%r3,%r2),0(%r4),%r0
+	jnz	1b
+3:	slgr	%r2,%r2
+	br	%r14
+4:	lghi	%r0,-4096
+	lgr	%r5,%r4
+	slgr	%r5,%r0
+	ngr	%r5,%r0		# %r5 = (%r4 + 4096) & -4096
+	slgr	%r5,%r4		# %r5 = #bytes to next user page boundary
+	clgr	%r3,%r5		# copy crosses next page boundary ?
+	jnh	6f		# no, the current page faulted
+	# move with the reduced length which is < 256
+5:	mvcp	0(%r5,%r2),0(%r4),%r0
+	slgr	%r3,%r5
+6:	lgr	%r2,%r3
+	br	%r14
         .section __ex_table,"a"
-	.quad	0b,2b
-	.quad	3b,1b
+	.quad	0b,4b
+	.quad	2b,4b
+	.quad	5b,6b
         .previous
 
         .align 4
         .text
         .globl __copy_to_user_asm
+	# %r2 = from, %r3 = n, %r4 = to
 __copy_to_user_asm:
-	lgr	%r5,%r3
-	sacf	512
-0:	mvcle	%r4,%r2,0
-	jo	0b
-1:	sacf	0
-	lgr	%r2,%r3
+	slgr	%r0,%r0
+0:	mvcs	0(%r3,%r4),0(%r2),%r0
+	jnz	1f
+	slgr	%r2,%r2
+	br	%r14
+1:	la	%r2,256(%r2)
+	la	%r4,256(%r4)
+	aghi	%r3,-256
+2:	mvcs	0(%r3,%r4),0(%r2),%r0
+	jnz	1b
+3:	slgr	%r2,%r2
 	br	%r14
-2:	lghi	%r1,-4096
+4:	lghi	%r0,-4096
 	lgr	%r5,%r4
-	slgr	%r5,%r1      # %r5 = %r4 + 4096
-	ngr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
-	slgr	%r5,%r4      # %r5 = #bytes to next user page boundary
-	clgr	%r3,%r5      # copy crosses next page boundary ?
-	jnh	1b           # no, the current page fauled
-	# The page after the current user page might have faulted.
-	# We cant't find out which page because the program check handler
-	# might have callled schedule, destroying all lowcore information.
-	# We retry with the shortened length.
-3:	mvcle	%r4,%r2,0
-	jo	3b
-	j	1b
+	slgr	%r5,%r0
+	ngr	%r5,%r0		# %r5 = (%r4 + 4096) & -4096
+	slgr	%r5,%r4		# %r5 = #bytes to next user page boundary
+	clgr	%r3,%r5		# copy crosses next page boundary ?
+	jnh	6f		# no, the current page faulted
+	# move with the reduced length which is < 256
+5:	mvcs	0(%r5,%r4),0(%r2),%r0
+	slgr	%r3,%r5
+6:	lgr	%r2,%r3
+	br	%r14
         .section __ex_table,"a"
-	.quad	0b,2b
-	.quad	3b,1b
+	.quad	0b,4b
+	.quad	2b,4b
+	.quad	5b,6b
         .previous
 
         .align 4
         .text
         .globl __copy_in_user_asm
+	# %r2 = from, %r3 = n, %r4 = to
 __copy_in_user_asm:
-	stmg	%r6,%r15,48(%r15)
-	lgr	%r5,%r3
-	lgr	%r7,%r5
-	lgr	%r6,%r2
-	cpya	6,4          # ar6 = ar4
-	sacf	512
-0:	mvcle	%r4,%r6,0
-	jo	0b
-1:	sacf	0
-	lgr	%r2,%r7
-	lmg	%r6,%r15,48(%r15)
+	sacf	256
+	bras	1,1f
+	mvc	0(1,%r4),0(%r2)
+0:	mvc	0(256,%r4),0(%r2)
+	la	%r2,256(%r2)
+	la	%r4,256(%r4)
+1:	aghi	%r3,-256
+	jnm	0b
+2:	ex	%r3,0(%r1)
+	sacf	0
+	slgr	%r2,%r2
+	br	14
+3:	mvc	0(1,%r4),0(%r2)
+	la	%r2,1(%r2)
+	la	%r4,1(%r4)
+	aghi	%r3,-1
+	jnm	3b
+4:	lgr	%r2,%r3
+	sacf	0
 	br	%r14
-2:	lghi	%r1,-4096
-	lgr	%r5,%r4
-	slgr	%r5,%r1      # %r5 = %r4 + 4096
-	ngr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
-	slgr	%r5,%r4      # %r5 = #bytes to next user page boundary
-	clgr	%r7,%r5      # copy crosses next page boundary ?
-	jnh	1b           # no, the current page fauled
-	# The page after the current user page might have faulted.
-	# We cant't find out which page because the program check handler
-	# might have callled schedule, destroying all lowcore information.
-	# We retry with the shortened length.
-3:	mvcle	%r4,%r6,0
-	jo	3b
-	j	1b
         .section __ex_table,"a"
-	.quad	0b,2b
-	.quad	3b,1b
+	.quad	0b,3b
+	.quad	2b,3b
+	.quad	3b,4b
         .previous
 
         .align 4
         .text
         .globl __clear_user_asm
+	# %r2 = to, %r3 = n
 __clear_user_asm:
+	slgr	%r0,%r0
+	larl	%r5,empty_zero_page
+1:	mvcs	0(%r3,%r2),0(%r5),%r0
+	jnz	2f
+	slgr	%r2,%r2
+	br	%r14
+2:	la	%r2,256(%r2)
+	aghi	%r3,-256
+3:	mvcs	0(%r3,%r2),0(%r5),%r0
+	jnz	2b
+4:	slgr	%r2,%r2
+	br	%r14
+5:	lghi	%r0,-4096
 	lgr	%r4,%r2
-	lgr	%r5,%r3
-	sgr	%r2,%r2
-	sgr	%r3,%r3
-	sacf	512
-0:	mvcle	%r4,%r2,0
-	jo	0b
-1:	sacf	0
-	br	%r14
-2:	lgr	%r2,%r5
-	lghi	%r1,-4096
-	slgr	%r5,%r1      # %r5 = %r4 + 4096
-	ngr	%r5,%r1      # %r5 = (%r4 + 4096) & -4096
-	slgr	%r5,%r4      # %r5 = #bytes to next user page boundary
-	clgr	%r2,%r5      # copy crosses next page boundary ?
-	jnh	1b           # no, the current page fauled
-	# The page after the current user page might have faulted.
-	# We cant't find out which page because the program check handler
-	# might have callled schedule, destroying all lowcore information.
-	# We retry with the shortened length.
-	slgr	%r2,%r5
-3:	mvcle	%r4,%r2,0
-	jo	3b
-	j	1b
-4:	algr	%r2,%r5
-	j	1b
+	slgr	%r4,%r0
+	ngr	%r4,%r0		# %r4 = (%r2 + 4096) & -4096
+	slgr	%r4,%r2		# %r4 = #bytes to next user page boundary
+	clgr	%r3,%r4		# clear crosses next page boundary ?
+	jnh	7f		# no, the current page faulted
+	# clear with the reduced length which is < 256
+6:	mvcs	0(%r4,%r2),0(%r5),%r0
+	slgr	%r3,%r4
+7:	lgr	%r2,%r3
+	br	%r14
         .section __ex_table,"a"
-	.quad	0b,2b
-        .quad	3b,4b
+	.quad	1b,5b
+	.quad	3b,5b
+	.quad	6b,7b
         .previous
+
+        .align 4
+        .text
+        .globl __strncpy_from_user_asm
+	# %r2 = dst, %r3 = src, %r4 = count
+__strncpy_from_user_asm:
+	lghi	%r0,0
+	lghi	%r1,1
+	lghi	%r5,0
+0:	mvcp	0(%r1,%r2),0(%r3),%r0
+	tm	0(%r2),0xff
+	jz	1f
+	la	%r2,1(%r2)
+	la	%r3,1(%r3)
+	aghi	%r5,1
+	clgr	%r5,%r4
+	jl	0b
+1:	lgr	%r2,%r5
+	br	%r14
+2:	lghi	%r2,-EFAULT
+	br	%r14
+        .section __ex_table,"a"
+	.quad	0b,2b
+	.previous
+
+        .align 4
+        .text
+        .globl __strnlen_user_asm
+	# %r2 = src, %r3 = count
+__strnlen_user_asm:
+	lghi	%r0,0
+	lghi	%r1,1
+	lghi	%r5,0
+0:	mvcp	24(%r1,%r15),0(%r2),%r0
+	aghi	%r5,1
+	tm	24(%r15),0xff
+	jz	1f
+	la	%r2,1(%r2)
+	clgr	%r5,%r3
+	jl	0b
+1:	lgr	%r2,%r5
+	br	%r14
+2:	lghi	%r2,-EFAULT
+	br	%r14
+        .section __ex_table,"a"
+	.quad	0b,2b
+	.previous
diff -Nru a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
--- a/arch/s390/mm/fault.c	Sat Apr  3 19:38:55 2004
+++ b/arch/s390/mm/fault.c	Sat Apr  3 19:38:55 2004
@@ -87,12 +87,12 @@
 	if (areg == 0)
 		/* Access via access register 0 -> kernel address */
 		return 0;
-	if (regs && areg < NUM_ACRS && regs->acrs[areg] <= 1)
+	if (regs && areg < NUM_ACRS && current->thread.acrs[areg] <= 1)
 		/*
 		 * access register contains 0 -> kernel address,
 		 * access register contains 1 -> user space address
 		 */
-		return regs->acrs[areg];
+		return current->thread.acrs[areg];
 
 	/* Something unhealthy was done with the access registers... */
 	die("page fault via unknown access register", regs, error_code);
@@ -115,8 +115,10 @@
 	 *   3: Home Segment Table Descriptor
 	 */
 	int descriptor = S390_lowcore.trans_exc_code & 3;
-	if (descriptor == 1)
+	if (descriptor == 1) {
+		save_access_regs(current->thread.acrs);
 		return __check_access_register(regs, error_code);
+	}
 	return descriptor >> 1;
 }
 
diff -Nru a/arch/s390/mm/init.c b/arch/s390/mm/init.c
--- a/arch/s390/mm/init.c	Sat Apr  3 19:38:54 2004
+++ b/arch/s390/mm/init.c	Sat Apr  3 19:38:54 2004
@@ -138,6 +138,8 @@
                 }
         }
 
+	S390_lowcore.kernel_asce = pgdir_k;
+
         /* enable virtual mapping in kernel mode */
         __asm__ __volatile__("    LCTL  1,1,%0\n"
                              "    LCTL  7,7,%0\n"
@@ -222,6 +224,8 @@
                         }
                 }
         }
+
+	S390_lowcore.kernel_asce = pgdir_k;
 
         /* enable virtual mapping in kernel mode */
         __asm__ __volatile__("lctlg 1,1,%0\n\t"
diff -Nru a/arch/sh/Kconfig b/arch/sh/Kconfig
--- a/arch/sh/Kconfig	Sat Apr  3 19:38:56 2004
+++ b/arch/sh/Kconfig	Sat Apr  3 19:38:56 2004
@@ -27,7 +27,6 @@
 
 source "init/Kconfig"
 
-
 menu "System type"
 
 choice
@@ -244,6 +243,19 @@
 	  turning this off will boot the kernel on these machines with the
 	  MMU implicitly switched off.
 
+choice
+	prompt "HugeTLB page size"
+	depends on HUGETLB_PAGE && CPU_SH4 && MMU
+	default HUGETLB_PAGE_SIZE_64K
+
+config HUGETLB_PAGE_SIZE_64K
+	bool "64K"
+
+config HUGETLB_PAGE_SIZE_1MB
+	bool "1MB"
+
+endchoice
+
 config CMDLINE_BOOL
 	bool "Default bootloader kernel arguments"
 
@@ -483,10 +495,9 @@
 	  People using multiprocessor machines who say Y here should also say
 	  Y to "Enhanced Real Time Clock Support", below.
 
-	  See also the <file:Documentation/smp.tex>,
-	  <file:Documentation/smp.txt>, <file:Documentation/nmi_watchdog.txt>
-	  and the SMP-HOWTO available at
-	  <http://www.tldp.org/docs.html#howto>.
+	  See also the <file:Documentation/smp.txt>,
+	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available
+	  at <http://www.tldp.org/docs.html#howto>.
 
 	  If you don't know what to do here, say N.
 
@@ -516,16 +527,20 @@
 	  with an auto-probed frequency which should be considered the proper
 	  value for your hardware.
 
+menu "CPU Frequency scaling"
+
 config CPU_FREQ
 	bool "CPU Frequency scaling"
 	help
 	  CPU clock scaling allows you to change the clock speed of the
 	  running CPU on the fly.
 
-	  For details, take a look at <file:Documentation/cpufreq>.
+	  For details, take a look at <file:Documentation/cpu-freq>.
 
 	  If unsure, say N.
 
+source "drivers/cpufreq/Kconfig"
+
 config CPU_FREQ_TABLE
 	tristate "CPU frequency table helpers"
 	depends on CPU_FREQ
@@ -543,16 +558,24 @@
 	  This adds the cpufreq driver for SuperH. At present, only
 	  the SH-4 is supported.
 
-	  For details, take a look at <file:Documentation/cpufreq>.
+	  For details, take a look at <file:Documentation/cpu-freq>.
 
 	  If unsure, say N.
 
-source "drivers/cpufreq/Kconfig"
+endmenu
 
 source "arch/sh/drivers/dma/Kconfig"
 
 source "arch/sh/cchips/Kconfig"
 
+config HEARTBEAT
+	bool "Heartbeat LED"
+	depends on SH_MPC1211 || SH_CAT68701 || SH_STB1_HARP || SH_STB1_OVERDRIVE || SH_BIGSUR || SH_7751_SOLUTION_ENGINE || SH_SOLUTION_ENGINE
+	help
+	  Use the power-on LED on your machine as a load meter.  The exact
+	  behavior is platform-dependent, but normally the flash frequency is
+	  a hyperbolic function of the 5-minute load average.
+
 endmenu
 
 
@@ -602,8 +625,9 @@
 	bool
 
 config MAPLE
-	bool
-	default y if SH_DREAMCAST
+	tristate "Maple Bus support"
+	depends on SH_DREAMCAST
+	default y
 
 source "arch/sh/drivers/pci/Kconfig"
 
@@ -622,350 +646,9 @@
 
 endmenu
 
-source "drivers/base/Kconfig"
-
-source "drivers/mtd/Kconfig"
-
-source "drivers/parport/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/ide/Kconfig"
-
-source "drivers/scsi/Kconfig"
-
-source "drivers/cdrom/Kconfig"
-
-source "drivers/md/Kconfig"
-
-source "drivers/ieee1394/Kconfig"
-
-source "net/Kconfig"
-
-source "drivers/isdn/Kconfig"
-
-source "drivers/telephony/Kconfig"
-
-#
-# input - input/joystick depends on it. As does USB.
-#
-source "drivers/input/Kconfig"
-
-menu "Character devices"
-
-config VT
-	bool "Virtual terminal"
-	---help---
-	  If you say Y here, you will get support for terminal devices with
-	  display and keyboard devices. These are called "virtual" because you
-	  can run several virtual terminals (also called virtual consoles) on
-	  one physical terminal. This is rather useful, for example one
-	  virtual terminal can collect system messages and warnings, another
-	  one can be used for a text-mode user session, and a third could run
-	  an X session, all in parallel. Switching between virtual terminals
-	  is done with certain key combinations, usually Alt-<function key>.
-
-	  The setterm command ("man setterm") can be used to change the
-	  properties (such as colors or beeping) of a virtual terminal. The
-	  man page console_codes(4) ("man console_codes") contains the special
-	  character sequences that can be used to change those properties
-	  directly. The fonts used on virtual terminals can be changed with
-	  the setfont ("man setfont") command and the key bindings are defined
-	  with the loadkeys ("man loadkeys") command.
-
-	  You need at least one virtual terminal device in order to make use
-	  of your keyboard and monitor. Therefore, only people configuring an
-	  embedded system would want to say N here in order to save some
-	  memory; the only way to log into such a system is then via a serial
-	  or network connection.
-
-	  If unsure, say Y, or else you won't be able to do much with your new
-	  shiny Linux system :-)
-
-config VT_CONSOLE
-	bool "Support for console on virtual terminal"
-	depends on VT
-	---help---
-	  The system console is the device which receives all kernel messages
-	  and warnings and which allows logins in single user mode. If you
-	  answer Y here, a virtual terminal (the device used to interact with
-	  a physical terminal) can be used as system console. This is the most
-	  common mode of operations, so you should say Y here unless you want
-	  the kernel messages be output only to a serial port (in which case
-	  you should say Y to "Console on serial port", below).
-
-	  If you do say Y here, by default the currently visible virtual
-	  terminal (/dev/tty0) will be used as system console. You can change
-	  that with a kernel command line option such as "console=tty3" which
-	  would use the third virtual terminal as system console. (Try "man
-	  bootparam" or see the documentation of your boot loader (lilo or
-	  loadlin) about how to pass options to the kernel at boot time.)
-
-	  If unsure, say Y.
-
-config HW_CONSOLE
-	bool
-	depends on VT && !S390 && !UM
-	default y
-
-config SERIAL
-	tristate "Serial (8250, 16450, 16550 or compatible) support"
-	---help---
-	  This selects whether you want to include the driver for the standard
-	  serial ports.  The standard answer is Y.  People who might say N
-	  here are those that are setting up dedicated Ethernet WWW/FTP
-	  servers, or users that have one of the various bus mice instead of a
-	  serial mouse and don't intend to use their machine's standard serial
-	  port for anything.  (Note that the Cyclades and Stallion multi
-	  serial port drivers do not need this driver built in for them to
-	  work.)
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called serial.
-	  [WARNING: Do not compile this driver as a module if you are using
-	  non-standard serial ports, since the configuration information will
-	  be lost when the driver is unloaded.  This limitation may be lifted
-	  in the future.]
-
-	  BTW1: If you have a mouseman serial mouse which is not recognized by
-	  the X window system, try running gpm first.
-
-	  BTW2: If you intend to use a software modem (also called Winmodem)
-	  under Linux, forget it.  These modems are crippled and require
-	  proprietary drivers which are only available under Windows.
-
-	  Most people will say Y or M here, so that they can use serial mice,
-	  modems and similar devices connecting to the standard serial ports.
-
-config SH_SCI
-	tristate "Serial (SCI, SCIF) support"
-	help
-	  Selecting this option will allow the Linux kernel to transfer data
-	  over SCI (Serial Communication Interface) and/or SCIF (Serial
-	  Communication Interface with FIFO) which are built into the Hitachi
-	  SuperH processor.  The option provides 1 to 3 (depending
-	  on the CPU model) standard Linux tty devices, /dev/ttySC[012]; one
-	  of these is normally used as the system console.
-
-	  If in doubt, press "y".
-
-config SERIAL_CONSOLE
-	bool "Support for console on serial port"
-	depends on SERIAL=y || SH_SCI=y
-	---help---
-	  If you say Y here, it will be possible to use a serial port as the
-	  system console (the system console is the device which receives all
-	  kernel messages and warnings and which allows logins in single user
-	  mode). This could be useful if some terminal or printer is connected
-	  to that serial port.
-
-	  Even if you say Y here, the currently visible virtual console
-	  (/dev/tty0) will still be used as the system console by default, but
-	  you can alter that using a kernel command line option such as
-	  "console=ttyS1". (Try "man bootparam" or see the documentation of
-	  your boot loader (lilo or loadlin) about how to pass options to the
-	  kernel at boot time.)
-
-	  If you don't have a VGA card installed and you say Y here, the
-	  kernel will automatically use the first serial line, /dev/ttyS0, as
-	  system console.
-
-	  If unsure, say N.
-
-comment "Unix98 PTY support"
-
-config UNIX98_PTYS
-	bool "Unix98 PTY support"
-	---help---
-	  A pseudo terminal (PTY) is a software device consisting of two
-	  halves: a master and a slave. The slave device behaves identical to
-	  a physical terminal; the master device is used by a process to
-	  read data from and write data to the slave, thereby emulating a
-	  terminal. Typical programs for the master side are telnet servers
-	  and xterms.
-
-	  Linux has traditionally used the BSD-like names /dev/ptyxx for
-	  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
-	  has a number of problems. The GNU C library glibc 2.1 and later,
-	  however, supports the Unix98 naming standard: in order to acquire a
-	  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
-	  terminal is then made available to the process and the pseudo
-	  terminal slave can be accessed as /dev/pts/<number>. What was
-	  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
-	  The entries in /dev/pts/ are created on the fly by a virtual
-	  file system; therefore, if you say Y here you should say Y to
-	  "/dev/pts file system for Unix98 PTYs" as well.
-
-	  If you want to say Y here, you need to have the C library glibc 2.1
-	  or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
-	  Read the instructions in <file:Documentation/Changes> pertaining to
-	  pseudo terminals. It's safe to say N.
-
-config UNIX98_PTY_COUNT
-	int "Maximum number of Unix98 PTYs in use (0-2048)"
-	depends on UNIX98_PTYS
-	default "256"
-	help
-	  The maximum number of Unix98 PTYs that can be used at any one time.
-	  The default is 256, and should be enough for desktop systems. Server
-	  machines which support incoming telnet/rlogin/ssh connections and/or
-	  serve several X terminals may want to increase this: every incoming
-	  connection and every xterm uses up one PTY.
-
-	  When not in use, each additional set of 256 PTYs occupy
-	  approximately 8 KB of kernel memory on 32-bit architectures.
-
-config HEARTBEAT
-	bool "Heartbeat LED"
-	depends on SH_MPC1211 || SH_CAT68701 || SH_STB1_HARP || SH_STB1_OVERDRIVE || SH_BIGSUR || SH_7751_SOLUTION_ENGINE || SH_SOLUTION_ENGINE
-	help
-	  Use the power-on LED on your machine as a load meter.  The exact
-	  behavior is platform-dependent, but normally the flash frequency is
-	  a hyperbolic function of the 5-minute load average.
-
-
-menu "Maple Bus input peripherals"
-	depends on SH_DREAMCAST && MAPLE
-
-config MAPLE_KEYBOARD
-	tristate "Maple Bus keyboard support"
-	depends on INPUT
-
-config MAPLE_MOUSE
-	tristate "Maple Bus mouse support"
-	depends on INPUT
-
-comment "Input core support is required for Maple input peripherals"
-	depends on INPUT=n
-
-endmenu
-
-config PRINTER
-	tristate "Parallel printer support"
-	depends on PARPORT
-	---help---
-	  If you intend to attach a printer to the parallel port of your Linux
-	  box (as opposed to using a serial printer; if the connector at the
-	  printer has 9 or 25 holes ["female"], then it's serial), say Y.
-	  Also read the Printing-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  It is possible to share one parallel port among several devices
-	  (e.g. printer and ZIP drive) and it is safe to compile the
-	  corresponding drivers into the kernel.
-	  To compile this driver as a module, choose M here and read
-	  <file:Documentation/parport.txt>.  The module will be called lp.
-
-	  If you have several parallel ports, you can specify which ports to
-	  use with the "lp" kernel command line option.  (Try "man bootparam"
-	  or see the documentation of your boot loader (lilo or loadlin) about
-	  how to pass options to the kernel at boot time.)  The syntax of the
-	  "lp" command line option can be found in <file:drivers/char/lp.c>.
-
-	  If you have more than 8 printers, you need to increase the LP_NO
-	  macro in lp.c and the PARPORT_MAX macro in parport.h.
-
-config LP_CONSOLE
-	bool "Support for console on line printer"
-	depends on PRINTER
-	---help---
-	  If you want kernel messages to be printed out as they occur, you
-	  can have a console on the printer. This option adds support for
-	  doing that; to actually get it to happen you need to pass the
-	  option "console=lp0" to the kernel at boot time.
-
-	  If the printer is out of paper (or off, or unplugged, or too
-	  busy..) the kernel will stall until the printer is ready again.
-	  By defining CONSOLE_LP_STRICT to 0 (at your own risk) you
-	  can make the kernel continue when this happens,
-	  but it'll lose the kernel messages.
-
-	  If unsure, say N.
-
-config PPDEV
-	tristate "Support for user-space parallel port device drivers"
-	depends on PARPORT
-	---help---
-	  Saying Y to this adds support for /dev/parport device nodes.  This
-	  is needed for programs that want portable access to the parallel
-	  port, for instance deviceid (which displays Plug-and-Play device
-	  IDs).
-
-	  This is the parallel port equivalent of SCSI generic support (sg).
-	  It is safe to say N to this -- it is not needed for normal printing
-	  or parallel port CD-ROM/disk support.
-
-	  To compile this support as a module, choose M here: the
-	  module will be called ppdev.
-
-	  If unsure, say N.
-
-config PSMOUSE
-	bool "PS/2 mouse (aka \"auxiliary device\") support"
-	---help---
-	  The PS/2 mouse connects to a special mouse port that looks much like
-	  the keyboard port (small circular connector with 6 pins). This way,
-	  the mouse does not use any serial ports. This port can also be used
-	  for other input devices like light pens, tablets, keypads. Compaq,
-	  AST and IBM all use this as their mouse port on currently shipping
-	  machines. The trackballs of some laptops are PS/2 mice also. In
-	  particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 mouse.
-
-	  Although PS/2 mice are not technically bus mice, they are explained
-	  in detail in the Busmouse-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.
-
-	  When using a PS/2 mouse, you can get problems if you want to use the
-	  mouse both on the Linux console and under X. Using the "-R" option
-	  of the Linux mouse managing program gpm (available from
-	  <ftp://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
-	  the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
-
-source "drivers/char/watchdog/Kconfig"
-
-config RTC
-	tristate "Enhanced Real Time Clock Support"
-	---help---
-	  If you say Y here and create a character special file /dev/rtc with
-	  major number 10 and minor number 135 using mknod ("man mknod"), you
-	  will get access to the real time clock (or hardware clock) built
-	  into your computer.
-
-	  Every PC has such a clock built in. It can be used to generate
-	  signals from as low as 1Hz up to 8192Hz, and can also be used
-	  as a 24 hour alarm. It reports status information via the file
-	  /proc/driver/rtc and its behaviour is set by various ioctls on
-	  /dev/rtc.
-
-	  If you run Linux on a multiprocessor machine and said Y to
-	  "Symmetric Multi Processing" above, you should say Y here to read
-	  and set the RTC in an SMP compatible fashion.
-
-	  If you think you have a use for such a device (such as periodic data
-	  sampling), then say Y here, and read <file:Documentation/rtc.txt>
-	  for details.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called rtc.
-
-source "drivers/char/pcmcia/Kconfig"
-
-source "drivers/serial/Kconfig"
-
-source "drivers/i2c/Kconfig"
- 
-endmenu
+source "drivers/Kconfig"
 
 source "fs/Kconfig"
-
-source "drivers/media/Kconfig"
-
-source "drivers/video/Kconfig"
-
-source "sound/Kconfig"
-
-source "drivers/usb/Kconfig"
 
 source "arch/sh/oprofile/Kconfig"
 
diff -Nru a/arch/sh/Makefile b/arch/sh/Makefile
--- a/arch/sh/Makefile	Sat Apr  3 19:38:45 2004
+++ b/arch/sh/Makefile	Sat Apr  3 19:38:45 2004
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.32 2003/10/26 23:33:49 lethal Exp $
+# $Id: Makefile,v 1.34 2004/03/21 17:31:06 lethal Exp $
 #
 # 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
@@ -35,7 +35,6 @@
 
 cflags-$(CONFIG_SH_DSP)			+= -Wa,-dsp
 cflags-$(CONFIG_SH_KGDB)		+= -g
-cflags-$(CONFIG_EMBEDDED)		+= -Os
 
 cflags-$(CONFIG_MORE_COMPILE_OPTIONS)	+= \
 	$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
@@ -134,19 +133,7 @@
 archclean:
 	$(Q)$(MAKE) $(clean)=$(boot)
 
-defconfig-%:
-	@echo '  Copying arch/sh/configs/$@ -> .config'
-	@if [ -e .config ]; then mv -f .config .config.old; fi
-	@cp -f arch/sh/configs/$@ .config
-	@chmod 644 .config
-
 define archhelp
-	@echo '  zImage		  - Compressed kernel image (arch/sh/boot/zImage)'
-	for board in arch/sh/configs/*; \
-	do \
-		 echo -n ' ' $$board | sed -e 's|arch/sh/configs/||g' ; \
-		 echo -n '  	  - Build for ' ; \
-		 echo -e $$board | sed -e 's|.*-||g'; \
-	done
+	@echo '  zImage 	           - Compressed kernel image (arch/sh/boot/zImage)'
 endef
 
diff -Nru a/arch/sh/boards/hp6xx/hp680/mach.c b/arch/sh/boards/hp6xx/hp680/mach.c
--- a/arch/sh/boards/hp6xx/hp680/mach.c	Sat Apr  3 19:38:56 2004
+++ b/arch/sh/boards/hp6xx/hp680/mach.c	Sat Apr  3 19:38:56 2004
@@ -21,29 +21,33 @@
 #include <asm/irq.h>
 
 struct sh_machine_vector mv_hp680 __initmv = {
-        .mv_nr_irqs             = HD64461_IRQBASE+HD64461_IRQ_NUM,
+	.mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
 
-        .mv_inb                 = hd64461_inb,
-        .mv_inw                 = hd64461_inw,
-        .mv_inl                 = hd64461_inl,
-        .mv_outb                = hd64461_outb,
-        .mv_outw                = hd64461_outw,
-        .mv_outl                = hd64461_outl,
-
-        .mv_inb_p               = hd64461_inb_p,
-        .mv_inw_p               = hd64461_inw,
-        .mv_inl_p               = hd64461_inl,
-        .mv_outb_p              = hd64461_outb_p,
-        .mv_outw_p              = hd64461_outw,
-        .mv_outl_p              = hd64461_outl,
-
-        .mv_insb                = hd64461_insb,
-        .mv_insw                = hd64461_insw,
-        .mv_insl                = hd64461_insl,
-        .mv_outsb               = hd64461_outsb,
-        .mv_outsw               = hd64461_outsw,
-        .mv_outsl               = hd64461_outsl,
+	.mv_inb = hd64461_inb,
+	.mv_inw = hd64461_inw,
+	.mv_inl = hd64461_inl,
+	.mv_outb = hd64461_outb,
+	.mv_outw = hd64461_outw,
+	.mv_outl = hd64461_outl,
 
-        .mv_irq_demux           = hd64461_irq_demux,
+	.mv_inb_p = hd64461_inb_p,
+	.mv_inw_p = hd64461_inw,
+	.mv_inl_p = hd64461_inl,
+	.mv_outb_p = hd64461_outb_p,
+	.mv_outw_p = hd64461_outw,
+	.mv_outl_p = hd64461_outl,
+
+	.mv_insb = hd64461_insb,
+	.mv_insw = hd64461_insw,
+	.mv_insl = hd64461_insl,
+	.mv_outsb = hd64461_outsb,
+	.mv_outsw = hd64461_outsw,
+	.mv_outsl = hd64461_outsl,
+
+	.mv_readw = hd64461_readw,
+	.mv_writew = hd64461_writew,
+
+	.mv_irq_demux = hd64461_irq_demux,
 };
+
 ALIAS_MV(hp680)
diff -Nru a/arch/sh/boards/hp6xx/hp680/setup.c b/arch/sh/boards/hp6xx/hp680/setup.c
--- a/arch/sh/boards/hp6xx/hp680/setup.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sh/boards/hp6xx/hp680/setup.c	Sat Apr  3 19:38:55 2004
@@ -12,6 +12,9 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <asm/hd64461/hd64461.h>
+#include <asm/io.h>
+#include <asm/hp6xx/hp6xx.h>
+#include <asm/cpu/dac.h>
 
 const char *get_system_type(void)
 {
@@ -20,8 +23,19 @@
 
 int __init platform_setup(void)
 {
-	__set_io_port_base(CONFIG_HD64461_IOBASE - HD64461_STBCR);
+	u16 v;
+	v = inw(HD64461_STBCR);
+	v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
+	    HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
+	    HD64461_STBCR_SAFEST | HD64461_STBCR_SPC0ST |
+	    HD64461_STBCR_SMIAST | HD64461_STBCR_SAFECKE_OST |
+	    HD64461_STBCR_SAFECKE_IST;
+	outw(v, HD64461_STBCR);
+	v = inw(HD64461_GPADR);
+	v |= HD64461_GPADR_SPEAKER | HD64461_GPADR_PCMCIA0;
+	outw(v, HD64461_GPADR);
+
+	sh_dac_disable(DAC_SPEAKER_VOLUME);
 
 	return 0;
 }
-
diff -Nru a/arch/sh/boards/se/770x/io.c b/arch/sh/boards/se/770x/io.c
--- a/arch/sh/boards/se/770x/io.c	Sat Apr  3 19:38:40 2004
+++ b/arch/sh/boards/se/770x/io.c	Sat Apr  3 19:38:40 2004
@@ -1,4 +1,4 @@
-/* $Id: io.c,v 1.4 2003/08/03 03:05:10 lethal Exp $
+/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
  *
  * linux/arch/sh/kernel/io_se.c
  *
@@ -134,25 +134,27 @@
 void se_insb(unsigned long port, void *addr, unsigned long count)
 {
 	volatile __u16 *p = port2adr(port);
+	__u8 *ap = addr;
 
 	if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) {
 		volatile __u8 *bp = (__u8 *) (sh_pcic_io_wbase + 0x40000 + port); 
 		while (count--)
-			*((__u8 *) addr)++ = *bp;
+			*ap++ = *bp;
 	} else if (shifted_port(port)) {
 		while (count--)
-			*((__u8 *) addr)++ = *p >> 8;
+			*ap++ = *p >> 8;
 	} else {
 		while (count--)
-			*((__u8 *) addr)++ = *p;
+			*ap++ = *p;
 	}
 }
 
 void se_insw(unsigned long port, void *addr, unsigned long count)
 {
 	volatile __u16 *p = port2adr(port);
+	__u16 *ap = addr;
 	while (count--)
-		*((__u16 *) addr)++ = *p;
+		*ap++ = *p;
 }
 
 void se_insl(unsigned long port, void *addr, unsigned long count)
@@ -163,25 +165,27 @@
 void se_outsb(unsigned long port, const void *addr, unsigned long count)
 {
 	volatile __u16 *p = port2adr(port);
+	const __u8 *ap = addr;
 
 	if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop) {
 		volatile __u8 *bp = (__u8 *) (sh_pcic_io_wbase + port); 
 		while (count--)
-			*bp = *((__u8 *) addr)++;
+			*bp = *ap++;
 	} else if (shifted_port(port)) {
 		while (count--)
-			*p = *((__u8 *) addr)++ << 8;
+			*p = *ap++ << 8;
 	} else {
 		while (count--)
-			*p = *((__u8 *) addr)++;
+			*p = *ap++;
 	}
 }
 
 void se_outsw(unsigned long port, const void *addr, unsigned long count)
 {
 	volatile __u16 *p = port2adr(port);
+	const __u16 *ap = addr;
 	while (count--)
-		*p = *((__u16 *) addr)++;
+		*p = *ap++;
 }
 
 void se_outsl(unsigned long port, const void *addr, unsigned long count)
diff -Nru a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c
--- a/arch/sh/boards/se/770x/irq.c	Sat Apr  3 19:38:56 2004
+++ b/arch/sh/boards/se/770x/irq.c	Sat Apr  3 19:38:56 2004
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.1.2.2 2002/10/29 00:56:09 lethal Exp $
+/* $Id: irq.c,v 1.4 2004/02/22 22:44:36 kkojima Exp $
  * 
  * linux/arch/sh/boards/se/770x/irq.c
  *
@@ -12,7 +12,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <asm/irq.h>
-#include <asm/hitachi_se.h>
+#include <asm/se/se.h>
 
 /*
  * Initialize IRQ setting
diff -Nru a/arch/sh/cchips/Kconfig b/arch/sh/cchips/Kconfig
--- a/arch/sh/cchips/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/sh/cchips/Kconfig	Sat Apr  3 19:38:55 2004
@@ -1,7 +1,13 @@
+menu "Companion Chips"
+
 # A board must have defined HD6446X_SERIES in order to see these
+config HD6446X_SERIES
+	bool "HD6446x support"
+	default n
+
 choice
 	prompt "HD6446x options"
-	depends HD6446X_SERIES
+	depends on HD6446X_SERIES
 	default HD64461
 
 config HD64461
@@ -73,4 +79,5 @@
 
 	  Do not change this unless you know what you are doing.
 
+endmenu
 
diff -Nru a/arch/sh/cchips/hd6446x/hd64461/io.c b/arch/sh/cchips/hd6446x/hd64461/io.c
--- a/arch/sh/cchips/hd6446x/hd64461/io.c	Sat Apr  3 19:38:45 2004
+++ b/arch/sh/cchips/hd6446x/hd64461/io.c	Sat Apr  3 19:38:45 2004
@@ -1,5 +1,5 @@
 /*
- *	$Id: io.c,v 1.5 2004/02/01 19:46:04 lethal Exp $
+ *	$Id: io.c,v 1.6 2004/03/16 00:07:50 lethal Exp $
  *	Copyright (C) 2000 YAEGASHI Takeshi
  *	Typical I/O routines for HD64461 system.
  */
@@ -8,6 +8,8 @@
 #include <asm/io.h>
 #include <asm/hd64461/hd64461.h>
 
+#define MEM_BASE (CONFIG_HD64461_IOBASE - HD64461_STBCR)
+
 static __inline__ unsigned long PORT2ADDR(unsigned long port)
 {
 	/* 16550A: HD64461 internal */
@@ -36,7 +38,9 @@
 #endif
 
 	/* ??? */
-	if (port < 0x10000) return 0xa0000000 + port;
+	if (port < 0xf000) return 0xa0000000 + port;
+	/* PCMCIA channel 0, I/O (0xba000000) */
+	if (port < 0x10000) return 0xba000000 + port - 0xf000;
 
 	/* HD64461 internal devices (0xb0000000) */
 	if (port < 0x20000) return CONFIG_HD64461_IOBASE + port - 0x10000;
@@ -140,3 +144,14 @@
 	const unsigned long *buf=buffer;
 	while(count--) *addr=*buf++;
 }
+
+unsigned short hd64461_readw(unsigned long addr)
+{
+	return *(volatile unsigned short*)(MEM_BASE+addr);
+}
+
+void hd64461_writew(unsigned short b, unsigned long addr)
+{
+	*(volatile unsigned short*)(MEM_BASE+addr) = b;
+}
+
diff -Nru a/arch/sh/cchips/hd6446x/hd64461/setup.c b/arch/sh/cchips/hd6446x/hd64461/setup.c
--- a/arch/sh/cchips/hd6446x/hd64461/setup.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sh/cchips/hd6446x/hd64461/setup.c	Sat Apr  3 19:38:55 2004
@@ -1,11 +1,12 @@
 /*
- *	$Id: setup.c,v 1.4 2003/08/03 03:05:10 lethal Exp $
+ *	$Id: setup.c,v 1.5 2004/03/16 00:07:50 lethal Exp $
  *	Copyright (C) 2000 YAEGASHI Takeshi
  *	Hitachi HD64461 companion chip support
  */
 
 #include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
 #include <linux/interrupt.h>
@@ -30,7 +31,6 @@
 	local_irq_restore(flags);
 }
 
-
 static void enable_hd64461_irq(unsigned int irq)
 {
 	unsigned long flags;
@@ -44,7 +44,6 @@
 	local_irq_restore(flags);
 }
 
-
 static void mask_and_ack_hd64461(unsigned int irq)
 {
 	disable_hd64461_irq(irq);
@@ -54,27 +53,23 @@
 #endif
 }
 
-
 static void end_hd64461_irq(unsigned int irq)
 {
 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
 		enable_hd64461_irq(irq);
 }
 
-
 static unsigned int startup_hd64461_irq(unsigned int irq)
-{ 
+{
 	enable_hd64461_irq(irq);
 	return 0;
 }
 
-
 static void shutdown_hd64461_irq(unsigned int irq)
 {
 	disable_hd64461_irq(irq);
 }
 
-
 static struct hw_interrupt_type hd64461_irq_type = {
 	.typename	= "HD64461-IRQ",
 	.startup	= startup_hd64461_irq,
@@ -85,7 +80,6 @@
 	.end		= end_hd64461_irq,
 };
 
-
 static irqreturn_t hd64461_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	printk(KERN_INFO
@@ -95,23 +89,52 @@
 	return IRQ_NONE;
 }
 
+static struct {
+	int (*func) (int, void *);
+	void *dev;
+} hd64461_demux[HD64461_IRQ_NUM];
+
+void hd64461_register_irq_demux(int irq,
+				int (*demux) (int irq, void *dev), void *dev)
+{
+	hd64461_demux[irq - HD64461_IRQBASE].func = demux;
+	hd64461_demux[irq - HD64461_IRQBASE].dev = dev;
+}
+
+EXPORT_SYMBOL(hd64461_register_irq_demux);
+
+void hd64461_unregister_irq_demux(int irq)
+{
+	hd64461_demux[irq - HD64461_IRQBASE].func = 0;
+}
+
+EXPORT_SYMBOL(hd64461_unregister_irq_demux);
+
 int hd64461_irq_demux(int irq)
 {
 	if (irq == CONFIG_HD64461_IRQ) {
 		unsigned short bit;
 		unsigned short nirr = inw(HD64461_NIRR);
 		unsigned short nimr = inw(HD64461_NIMR);
+		int i;
+
 		nirr &= ~nimr;
-		for (bit = 1, irq = 0; irq < 16; bit <<= 1, irq++)
-			if (nirr & bit) break;
-		if (irq == 16) irq = CONFIG_HD64461_IRQ;
-		else irq += HD64461_IRQBASE;
+		for (bit = 1, i = 0; i < 16; bit <<= 1, i++)
+			if (nirr & bit)
+				break;
+		if (i == 16)
+			irq = CONFIG_HD64461_IRQ;
+		else {
+			irq = HD64461_IRQBASE + i;
+			if (hd64461_demux[i].func != 0) {
+				irq = hd64461_demux[i].func(irq, hd64461_demux[i].dev);
+			}
+		}
 	}
 	return __irq_demux(irq);
 }
 
-static struct irqaction irq0  = { hd64461_interrupt, SA_INTERRUPT, 0, "HD64461", NULL, NULL};
-
+static struct irqaction irq0 = { hd64461_interrupt, SA_INTERRUPT, 0, "HD64461", NULL, NULL };
 
 int __init setup_hd64461(void)
 {
@@ -120,11 +143,12 @@
 	if (!MACH_HD64461)
 		return 0;
 
-	printk(KERN_INFO "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
-	       CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ,
-	       HD64461_IRQBASE, HD64461_IRQBASE+15);
+	printk(KERN_INFO
+	       "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
+	       CONFIG_HD64461_IOBASE, CONFIG_HD64461_IRQ, HD64461_IRQBASE,
+	       HD64461_IRQBASE + 15);
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7709) /* Should be at processor specific part.. */
+#if defined(CONFIG_CPU_SUBTYPE_SH7709)	/* Should be at processor specific part.. */
 	outw(0x2240, INTC_ICR1);
 #endif
 	outw(0xffff, HD64461_NIMR);
diff -Nru a/arch/sh/configs/adx_defconfig b/arch/sh/configs/adx_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/configs/adx_defconfig	Sat Apr  3 19:38:43 2004
@@ -0,0 +1,276 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor type and features
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+CONFIG_SH_ADX=y
+# CONFIG_SH_UNKNOWN is not set
+CONFIG_SH_RTC=y
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+CONFIG_CPU_SUBTYPE_SH7750=y
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x00400000
+CONFIG_MEMORY_SET=y
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+CONFIG_ISA=y
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+# CONFIG_NET is not set
+CONFIG_CF_ENABLER=y
+# CONFIG_CF_AREA5 is not set
+CONFIG_CF_AREA6=y
+CONFIG_CF_BASE_ADDR=0xb8000000
+# CONFIG_HD64461 is not set
+# CONFIG_HD64465 is not set
+# CONFIG_SH_DMA is not set
+# CONFIG_PCI is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD 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_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+CONFIG_SH_SCI=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_PSMOUSE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_SH_STANDARD_BIOS=y
+CONFIG_SH_EARLY_PRINTK=y
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
diff -Nru a/arch/sh/configs/cqreek_defconfig b/arch/sh/configs/cqreek_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/configs/cqreek_defconfig	Sat Apr  3 19:38:45 2004
@@ -0,0 +1,274 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor type and features
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+CONFIG_SH_CQREEK=y
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_UNKNOWN is not set
+CONFIG_SH_RTC=y
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+CONFIG_CPU_SUBTYPE_SH7708=y
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+CONFIG_CPU_SH3=y
+# CONFIG_CPU_SH4 is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x00400000
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+CONFIG_ISA=y
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+# CONFIG_NET is not set
+# CONFIG_CF_AREA5 is not set
+CONFIG_CF_AREA6=y
+CONFIG_CF_BASE_ADDR=0xb8000000
+# CONFIG_HD64461 is not set
+# CONFIG_HD64465 is not set
+# CONFIG_SH_DMA is not set
+# CONFIG_PCI is not set
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD 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_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+CONFIG_SH_SCI=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_PSMOUSE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_ZLIB_FS_INFLATE is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_SH_STANDARD_BIOS=y
+CONFIG_SH_EARLY_PRINTK=y
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
diff -Nru a/arch/sh/configs/defconfig-adx b/arch/sh/configs/defconfig-adx
--- a/arch/sh/configs/defconfig-adx	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,276 +0,0 @@
-#
-# Automatically generated by make menuconfig: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# Processor type and features
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-CONFIG_SH_ADX=y
-# CONFIG_SH_UNKNOWN is not set
-CONFIG_SH_RTC=y
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-CONFIG_CPU_SUBTYPE_SH7750=y
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-# CONFIG_CPU_SH3 is not set
-CONFIG_CPU_SH4=y
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_MEMORY_START=0x08000000
-CONFIG_MEMORY_SIZE=0x00400000
-CONFIG_MEMORY_SET=y
-# CONFIG_DISCONTIGMEM is not set
-
-#
-# General setup
-#
-CONFIG_ISA=y
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-# CONFIG_NET is not set
-CONFIG_CF_ENABLER=y
-# CONFIG_CF_AREA5 is not set
-CONFIG_CF_AREA6=y
-CONFIG_CF_BASE_ADDR=0xb8000000
-# CONFIG_HD64461 is not set
-# CONFIG_HD64465 is not set
-# CONFIG_SH_DMA is not set
-# CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD 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_CISS_SCSI_TAPE is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-CONFIG_SH_STANDARD_BIOS=y
-CONFIG_SH_EARLY_PRINTK=y
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
diff -Nru a/arch/sh/configs/defconfig-cqreek b/arch/sh/configs/defconfig-cqreek
--- a/arch/sh/configs/defconfig-cqreek	Sat Apr  3 19:38:45 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,274 +0,0 @@
-#
-# Automatically generated by make menuconfig: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# Processor type and features
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-CONFIG_SH_CQREEK=y
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
-# CONFIG_SH_UNKNOWN is not set
-CONFIG_SH_RTC=y
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-CONFIG_CPU_SUBTYPE_SH7708=y
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-# CONFIG_DISCONTIGMEM is not set
-
-#
-# General setup
-#
-CONFIG_ISA=y
-# CONFIG_EISA is not set
-# CONFIG_MCA is not set
-# CONFIG_SBUS is not set
-# CONFIG_NET is not set
-# CONFIG_CF_AREA5 is not set
-CONFIG_CF_AREA6=y
-CONFIG_CF_BASE_ADDR=0xb8000000
-# CONFIG_HD64461 is not set
-# CONFIG_HD64465 is not set
-# CONFIG_SH_DMA is not set
-# CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_KCORE_ELF=y
-# CONFIG_KCORE_AOUT is not set
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD 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_CISS_SCSI_TAPE is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# ATA/IDE/MFM/RLL support
-#
-CONFIG_IDE=y
-
-#
-# IDE, ATA and ATAPI Block devices
-#
-CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_HD_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
-# CONFIG_BLK_DEV_IDECS is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_BLK_DEV_CMD640 is not set
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-# CONFIG_BLK_DEV_ISAPNP is not set
-# CONFIG_IDE_CHIPSETS is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_ATARAID is not set
-# CONFIG_BLK_DEV_ATARAID_PDC is not set
-# CONFIG_BLK_DEV_ATARAID_HPT is not set
-
-#
-# SCSI support
-#
-# CONFIG_SCSI is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Input core support
-#
-# CONFIG_INPUT is not set
-# CONFIG_INPUT_KEYBDEV is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-# CONFIG_UNIX98_PTYS is not set
-
-#
-# Joysticks
-#
-# CONFIG_INPUT_GAMEPORT is not set
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-
-#
-# File systems
-#
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_ADFS_FS is not set
-# CONFIG_ADFS_FS_RW is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_JBD_DEBUG is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-# CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-# CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
-# CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-# CONFIG_NLS is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-CONFIG_SH_STANDARD_BIOS=y
-CONFIG_SH_EARLY_PRINTK=y
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
diff -Nru a/arch/sh/configs/defconfig-dreamcast b/arch/sh/configs/defconfig-dreamcast
--- a/arch/sh/configs/defconfig-dreamcast	Sat Apr  3 19:38:44 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,584 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-# CONFIG_STANDALONE is not set
-CONFIG_BROKEN=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-CONFIG_SH_DREAMCAST=y
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
-CONFIG_CPU_SH4=y
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-CONFIG_CPU_SUBTYPE_SH7750=y
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_PREEMPT=y
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-CONFIG_SH_STORE_QUEUES=y
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_FREQ=49876504
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_TABLE=y
-CONFIG_SH_CPU_FREQ=y
-# CONFIG_CPU_FREQ_PROC_INTF is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-CONFIG_CPU_FREQ_GOV_USERSPACE=y
-CONFIG_SH_DMA=y
-CONFIG_NR_ONCHIP_DMA_CHANNELS=4
-CONFIG_NR_DMA_CHANNELS_BOOL=y
-CONFIG_NR_DMA_CHANNELS=9
-CONFIG_DMA_PAGE_OPS=y
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-CONFIG_PCI=y
-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Block devices
-#
-# 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 is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=1024
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 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 is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER 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 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=y
-# CONFIG_STNIC is not set
-# 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 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_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 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_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# 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_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 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_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_RCPCI 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_BOOL is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# 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
-#
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-
-#
-# Unix 98 PTY support
-#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_SH_SCI 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
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD 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=y
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS 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_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=y
-# 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 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# 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 is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# 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_ASILIANT is not set
-# CONFIG_FB_IMSTT is not set
-CONFIG_FB_PVR2=y
-# CONFIG_FB_PVR2_DEBUG is not set
-# CONFIG_FB_E1355 is not set
-# CONFIG_FB_RIVA is not set
-# CONFIG_FB_MATROX 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_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
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Profiling support
-#
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-CONFIG_ZLIB_INFLATE=y
diff -Nru a/arch/sh/configs/defconfig-hp680 b/arch/sh/configs/defconfig-hp680
--- a/arch/sh/configs/defconfig-hp680	Sat Apr  3 19:38:56 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,428 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-# CONFIG_STANDALONE is not set
-CONFIG_BROKEN=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_LOG_BUF_SHIFT=14
-# 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
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-CONFIG_SH_HP680=y
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-CONFIG_CPU_SUBTYPE_SH7709=y
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-# CONFIG_SH_DSP is not set
-CONFIG_SH_HP600=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_FREQ=1193182
-# CONFIG_CPU_FREQ is not set
-# CONFIG_SH_DMA is not set
-CONFIG_HD64461=y
-# CONFIG_HD64465 is not set
-CONFIG_HD64461_IRQ=36
-CONFIG_HD64461_ENABLER=y
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-# CONFIG_PCI is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_LOOP is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD 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 is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-# CONFIG_IDE_TASKFILE_IO is not set
-
-#
-# IDE chipset support/bugfixes
-#
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Networking support
-#
-# CONFIG_NET is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-
-#
-# 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 is not set
-# 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
-
-#
-# 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 is not set
-CONFIG_SH_SCI=y
-# CONFIG_SERIAL_CONSOLE is not set
-
-#
-# Unix 98 PTY support
-#
-# CONFIG_UNIX98_PTYS is not set
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_SH_SCI 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
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD 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 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_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_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
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-
-#
-# Graphics support
-#
-CONFIG_FB=y
-# CONFIG_FB_E1355 is not set
-CONFIG_FB_HIT=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_MDA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_PCI_CONSOLE=y
-CONFIG_FONTS=y
-# CONFIG_FONT_8x8 is not set
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_6x11 is not set
-CONFIG_FONT_PEARL_8x8=y
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
diff -Nru a/arch/sh/configs/defconfig-se7751 b/arch/sh/configs/defconfig-se7751
--- a/arch/sh/configs/defconfig-se7751	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,617 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=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=14
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-CONFIG_SH_7751_SOLUTION_ENGINE=y
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
-CONFIG_CPU_SH4=y
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-CONFIG_CPU_SUBTYPE_SH7751=y
-# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-CONFIG_MMU=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC1,38400"
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x04000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-CONFIG_ZERO_PAGE_OFFSET=0x00010000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_FREQ=60013568
-# CONFIG_CPU_FREQ is not set
-# CONFIG_SH_DMA is not set
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-CONFIG_PCI=y
-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_DMA=y
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES is not set
-# CONFIG_HOTPLUG is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
-# CONFIG_MTD_CONCAT is not set
-# CONFIG_MTD_REDBOOT_PARTS is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-# CONFIG_MTD_CHAR is not set
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
-CONFIG_MTD_GEN_PROBE=y
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-CONFIG_MTD_CFI_AMDSTD=y
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_RAM=y
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_MPC1211 is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# 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 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 is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-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=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# 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=y
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-CONFIG_IP_NF_QUEUE=y
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES 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 is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_STNIC is not set
-# 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 is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 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 is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# 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_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 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_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_RCPCI 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_BOOL is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-
-#
-# Unix 98 PTY support
-#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_HEARTBEAT=y
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
-# CONFIG_SH_WDT is not set
-# CONFIG_RTC is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_SH_SCI 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
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD 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 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_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
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND 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 is not set
-# CONFIG_NFSD is not set
-# CONFIG_EXPORTFS is not set
-# 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 is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
diff -Nru a/arch/sh/configs/defconfig-snapgear b/arch/sh/configs/defconfig-snapgear
--- a/arch/sh/configs/defconfig-snapgear	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,540 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_STANDALONE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_LOG_BUF_SHIFT=14
-# 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
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
-# CONFIG_SH_MPC1211 is not set
-CONFIG_SH_SECUREEDGE5410=y
-# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
-CONFIG_CPU_SH4=y
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-CONFIG_CPU_SUBTYPE_SH7751=y
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_MEMORY_START=0x08000000
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_FREQ=60013568
-# CONFIG_CPU_FREQ is not set
-CONFIG_SH_DMA=y
-CONFIG_NR_DMA_CHANNELS=8
-# CONFIG_DMA_PAGE_OPS is not set
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-CONFIG_PCI=y
-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_DMA=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# 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 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 is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_UNIX is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_NETFILTER 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_LLC 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 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_STNIC is not set
-# 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 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_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 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_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# 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_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 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_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 (depends on LLC=y)
-#
-# CONFIG_RCPCI 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
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN_BOOL 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 is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO 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 is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-
-#
-# Unix 98 PTY support
-#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_SH_SCI is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Hardware Sensors Mainboard support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD 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=y
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS 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_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=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_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=y
-# 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 is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_EXPORTFS is not set
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-# 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 is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-# CONFIG_CRC32 is not set
-CONFIG_ZLIB_INFLATE=y
diff -Nru a/arch/sh/configs/defconfig-systemh b/arch/sh/configs/defconfig-systemh
--- a/arch/sh/configs/defconfig-systemh	Sat Apr  3 19:38:54 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,372 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-# CONFIG_STANDALONE is not set
-CONFIG_BROKEN=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_SWAP=y
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_IKCONFIG is not set
-CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-CONFIG_SH_7751_SYSTEMH=y
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
-CONFIG_CPU_SH4=y
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-CONFIG_CPU_SUBTYPE_SH7751=y
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_PREEMPT=y
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_FREQ=49876504
-# CONFIG_CPU_FREQ is not set
-# CONFIG_SH_DMA is not set
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-CONFIG_PCI=y
-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_DMA=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
-# CONFIG_HOTPLUG is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Generic Driver Options
-#
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Block devices
-#
-# 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 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=1024
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_LBD is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# IEEE 1394 (FireWire) support (EXPERIMENTAL)
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# Networking support
-#
-# CONFIG_NET is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# ISDN subsystem
-#
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Userland interfaces
-#
-
-#
-# 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
-#
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL is not set
-CONFIG_SH_SCI=y
-CONFIG_SERIAL_CONSOLE=y
-
-#
-# Unix 98 PTY support
-#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_PSMOUSE is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_SH_SCI 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
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD 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=y
-# CONFIG_QUOTA is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS 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_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=y
-# 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
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_KGDB is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-CONFIG_CRC32=y
-CONFIG_ZLIB_INFLATE=y
diff -Nru a/arch/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/configs/dreamcast_defconfig	Sat Apr  3 19:38:44 2004
@@ -0,0 +1,715 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+# CONFIG_STANDALONE is not set
+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=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+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=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+CONFIG_SH_DREAMCAST=y
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+CONFIG_CPU_SUBTYPE_SH7750=y
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+CONFIG_MMU=y
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_PREEMPT=y
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+CONFIG_SH_OCRAM=y
+CONFIG_SH_STORE_QUEUES=y
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_FREQ=49876504
+
+#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+# CONFIG_CPU_FREQ_PROC_INTF is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_24_API is not set
+CONFIG_CPU_FREQ_TABLE=y
+CONFIG_SH_CPU_FREQ=y
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=4
+CONFIG_NR_DMA_CHANNELS_BOOL=y
+CONFIG_NR_DMA_CHANNELS=9
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_MAPLE=y
+CONFIG_PCI=y
+# CONFIG_SH_PCIDMA_NONCOHERENT is not set
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_FW_LOADER is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT 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 is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# 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 is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER 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 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=y
+# CONFIG_STNIC is not set
+# 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 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 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=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=1
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# 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_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 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_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_RCPCI 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
+
+#
+# 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 is not set
+# 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=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_MAPLE is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_MAPLE 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 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+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=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SH_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# 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_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_PVR2=y
+# CONFIG_FB_E1355 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 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_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Maple Bus input peripherals
+#
+# CONFIG_MAPLE_KEYBOARD is not set
+# CONFIG_MAPLE_MOUSE is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD 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=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS 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_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG 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=y
+# 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 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_GSS is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
diff -Nru a/arch/sh/configs/hp680_defconfig b/arch/sh/configs/hp680_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/configs/hp680_defconfig	Sat Apr  3 19:38:56 2004
@@ -0,0 +1,418 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+# CONFIG_STANDALONE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# 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
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+CONFIG_SH_HP680=y
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+CONFIG_CPU_SH3=y
+# CONFIG_CPU_SH4 is not set
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+CONFIG_CPU_SUBTYPE_SH7709=y
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+CONFIG_MMU=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x00400000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_SH_RTC=y
+# CONFIG_SH_DSP is not set
+CONFIG_SH_HP600=y
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_PREEMPT is not set
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_FREQ=1193182
+# CONFIG_CPU_FREQ is not set
+# CONFIG_SH_DMA is not set
+CONFIG_HD6446X_SERIES=y
+CONFIG_HD64461=y
+# CONFIG_HD64465 is not set
+CONFIG_HD64461_IRQ=36
+# CONFIG_HD64461_ENABLER is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+# CONFIG_HOTPLUG is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD 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 is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY 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_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Networking support
+#
+# CONFIG_NET is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# 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 is not set
+# 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
+
+#
+# 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
+
+#
+# Unix98 PTY support
+#
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_PSMOUSE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD 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 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_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_E1355 is not set
+CONFIG_FB_HIT=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+CONFIG_FONT_PEARL_8x8=y
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
diff -Nru a/arch/sh/configs/se7751_defconfig b/arch/sh/configs/se7751_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/configs/se7751_defconfig	Sat Apr  3 19:38:43 2004
@@ -0,0 +1,617 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=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=14
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+CONFIG_SH_7751_SOLUTION_ENGINE=y
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+CONFIG_MMU=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,38400"
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_SH_RTC=y
+CONFIG_ZERO_PAGE_OFFSET=0x00010000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_PREEMPT is not set
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_FREQ=60013568
+# CONFIG_CPU_FREQ is not set
+# CONFIG_SH_DMA is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+# CONFIG_SH_PCIDMA_NONCOHERENT is not set
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+CONFIG_PCI_DMA=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_HOTPLUG is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+# CONFIG_MTD_CHAR is not set
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_MPC1211 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# 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 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 is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+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=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# 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=y
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+CONFIG_IP_NF_QUEUE=y
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# 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 is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 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 is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# 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_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 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_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_RCPCI 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_BOOL is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Userland interfaces
+#
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 is not set
+
+#
+# Input Device Drivers
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+CONFIG_SH_SCI=y
+CONFIG_SERIAL_CONSOLE=y
+
+#
+# Unix 98 PTY support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_HEARTBEAT=y
+# CONFIG_PSMOUSE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_SH_WDT is not set
+# CONFIG_RTC is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI 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
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD 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 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_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
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND 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 is not set
+# CONFIG_NFSD is not set
+# CONFIG_EXPORTFS is not set
+# 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 is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff -Nru a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/configs/snapgear_defconfig	Sat Apr  3 19:38:55 2004
@@ -0,0 +1,540 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# 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
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+CONFIG_SH_SECUREEDGE5410=y
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+CONFIG_MMU=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_MEMORY_SET=y
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_SH_RTC=y
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_PREEMPT is not set
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_FREQ=60013568
+# CONFIG_CPU_FREQ is not set
+CONFIG_SH_DMA=y
+CONFIG_NR_DMA_CHANNELS=8
+# CONFIG_DMA_PAGE_OPS is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+# CONFIG_SH_PCIDMA_NONCOHERENT is not set
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+CONFIG_PCI_DMA=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# 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 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 is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+# CONFIG_UNIX is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER 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_LLC 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 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_STNIC is not set
+# 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 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_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 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_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# 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_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 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_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 (depends on LLC=y)
+#
+# CONFIG_RCPCI 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
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN_BOOL 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 is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO 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 is not set
+# CONFIG_SERIAL is not set
+CONFIG_SH_SCI=y
+CONFIG_SERIAL_CONSOLE=y
+
+#
+# Unix 98 PTY support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_PSMOUSE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# I2C Hardware Sensors Mainboard support
+#
+
+#
+# I2C Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD 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=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS 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_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=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_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# 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 is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_GSS is not set
+# 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 is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
diff -Nru a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/configs/systemh_defconfig	Sat Apr  3 19:38:54 2004
@@ -0,0 +1,372 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_SUPERH=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+# CONFIG_STANDALONE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+# CONFIG_SYSVIPC is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_SYSCTL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+CONFIG_SH_7751_SYSTEMH=y
+# CONFIG_SH_STB1_HARP is not set
+# CONFIG_SH_STB1_OVERDRIVE is not set
+# CONFIG_SH_HP620 is not set
+# CONFIG_SH_HP680 is not set
+# CONFIG_SH_HP690 is not set
+# CONFIG_SH_CQREEK is not set
+# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_CAT68701 is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_SH2000 is not set
+# CONFIG_SH_ADX is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_CPU_SH2 is not set
+# CONFIG_CPU_SH3 is not set
+CONFIG_CPU_SH4=y
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+CONFIG_MMU=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x00400000
+# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_SH_RTC=y
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_PREEMPT=y
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+# CONFIG_SH_STORE_QUEUES is not set
+# CONFIG_SMP is not set
+CONFIG_SH_PCLK_FREQ=49876504
+# CONFIG_CPU_FREQ is not set
+# CONFIG_SH_DMA is not set
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+CONFIG_PCI=y
+# CONFIG_SH_PCIDMA_NONCOHERENT is not set
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+CONFIG_PCI_DMA=y
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Block devices
+#
+# 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 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# Networking support
+#
+# CONFIG_NET is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Userland interfaces
+#
+
+#
+# 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
+#
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+CONFIG_SH_SCI=y
+CONFIG_SERIAL_CONSOLE=y
+
+#
+# Unix 98 PTY support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_PSMOUSE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SH_SCI 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
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD 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=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS 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_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# 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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_KGDB is not set
+# CONFIG_FRAME_POINTER is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
diff -Nru a/arch/sh/defconfig b/arch/sh/defconfig
--- a/arch/sh/defconfig	Sat Apr  3 19:38:43 2004
+++ b/arch/sh/defconfig	Sat Apr  3 19:38:43 2004
@@ -152,7 +152,6 @@
 CONFIG_IDE_GENERIC=y
 # CONFIG_BLK_DEV_IDEDMA is not set
 # CONFIG_IDEDMA_AUTO is not set
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
diff -Nru a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
--- a/arch/sh/drivers/dma/Kconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/sh/drivers/dma/Kconfig	Sat Apr  3 19:38:42 2004
@@ -1,3 +1,5 @@
+menu "DMA support"
+
 config SH_DMA
 	bool "DMA controller (DMAC) support"
 	help
@@ -34,9 +36,20 @@
 
 config DMA_PAGE_OPS
 	bool "Use DMAC for page copy/clear"
-	depends on SH_DMA
+	depends on SH_DMA && BROKEN
 	help
 	  Selecting this option will use a dual-address mode configured channel
 	  in the SH DMAC for copy_page()/clear_page(). Primarily a performance
 	  hack.
+
+config DMA_PAGE_OPS_CHANNEL
+	depends on DMA_PAGE_OPS
+	int "DMA channel for sh memory-manager page copy/clear"
+	default "3"
+	help
+	  This allows the specification of the dual address dma channel,
+	  in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
+	  are dual-address capable.
+
+endmenu
 
diff -Nru a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c
--- a/arch/sh/drivers/dma/dma-api.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sh/drivers/dma/dma-api.c	Sat Apr  3 19:38:55 2004
@@ -104,6 +104,11 @@
 {
 	struct dma_info *info = get_dma_info(chan);
 
+	if (info->tei_capable) {
+		wait_event(info->wait_queue, (info->ops->get_residue(info) == 0));
+		return;
+	}
+
 	while (info->ops->get_residue(info))
 		cpu_relax();
 }
@@ -161,6 +166,7 @@
 		info->chan = i;
 
 		init_MUTEX(&info->sem);
+		init_waitqueue_head(&info->wait_queue);
 	}
 
 	return 0;
diff -Nru a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
--- a/arch/sh/drivers/dma/dma-sh.c	Sat Apr  3 19:38:56 2004
+++ b/arch/sh/drivers/dma/dma-sh.c	Sat Apr  3 19:38:56 2004
@@ -55,9 +55,9 @@
 } __attribute__ ((aligned(16)));
 
 struct sh_dmac_info {
-        struct sh_dmac_channel channel[MAX_DMAC_CHANNELS];
+        struct sh_dmac_channel channel[4];
         unsigned long dmaor;
-} __attribute__ ((packed));
+};
 
 static volatile struct sh_dmac_info *sh_dmac = (volatile struct sh_dmac_info *)SH_DMAC_BASE;
 
@@ -74,25 +74,12 @@
 	if (chan < 4) {
 		irq = DMTE0_IRQ + chan;
 	} else {
-		irq = DMTE4_IRQ + chan;
+		irq = DMTE4_IRQ + chan - 4;
 	}
 
 	return irq;
 }
 
-static inline int get_dmte_chan(unsigned int irq)
-{
-	int chan;
-
-	if ((irq - DMTE4_IRQ) < 0) {
-		chan = irq - DMTE0_IRQ;
-	} else {
-		chan = irq - DMTE4_IRQ + 4;
-	}
-
-	return chan;
-}
-
 /*
  * We determine the correct shift size based off of the CHCR transmit size
  * for the given channel. Since we know that it will take:
@@ -106,54 +93,42 @@
 	return ts_shift[(sh_dmac->channel[info->chan].chcr >> 4) & 0x0007];
 }
 
+/*
+ * The transfer end interrupt must read the chcr register to end the
+ * hardware interrupt active condition.
+ * Besides that it needs to waken any waiting process, which should handle
+ * setting up the next transfer.
+ */
 static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs)
 {
-	
-	int chan = get_dmte_chan(irq);
-	struct dma_info *info = get_dma_info(chan);
+	struct dma_info * info = (struct dma_info *)dev_id;
+	u32 chcr = sh_dmac->channel[info->chan].chcr;
 
-	if (info->sar)
-		sh_dmac->channel[info->chan].sar = info->sar;
-	if (info->dar)
-		sh_dmac->channel[info->chan].sar = info->dar;
+	if (!(chcr & CHCR_TE))
+		return IRQ_NONE;
 
-	sh_dmac->channel[info->chan].dmatcr = info->count >> calc_xmit_shift(info);
-	sh_dmac->channel[info->chan].chcr &= ~CHCR_TE;
+	sh_dmac->channel[info->chan].chcr = chcr & ~(CHCR_IE | CHCR_DE);
 
-	disable_irq(irq);
+	wake_up(&info->wait_queue);
 
 	return IRQ_HANDLED;
 }
 
-static struct irqaction irq_tei = {
-	.name		= "DMAC Transfer End",
-	.handler	= dma_tei,
-	.flags		= SA_INTERRUPT,
-};
-
 static int sh_dmac_request_dma(struct dma_info *info)
 {
-	int irq = get_dmte_irq(info->chan);
-	char *p = (char *)((&irq_tei)->name);
-
-	sprintf(p, "%s (Channel %d)", p, info->chan);
-
-	make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
-
-	return setup_irq(irq, &irq_tei);
+	return request_irq(get_dmte_irq(info->chan), dma_tei,
+			   SA_INTERRUPT, "DMAC Transfer End", info);
 }
 
 static void sh_dmac_free_dma(struct dma_info *info)
 {
-	free_irq(get_dmte_irq(info->chan), 0);
+	free_irq(get_dmte_irq(info->chan), info);
 }
 
 static void sh_dmac_configure_channel(struct dma_info *info, unsigned long chcr)
 {
-	if (!chcr) {
-		chcr = sh_dmac->channel[info->chan].chcr;
-		chcr |= /* CHCR_IE | */ RS_DUAL;
-	}
+	if (!chcr)
+		chcr = RS_DUAL;
 
 	sh_dmac->channel[info->chan].chcr = chcr;
 
@@ -162,12 +137,18 @@
 
 static void sh_dmac_enable_dma(struct dma_info *info)
 {
-	sh_dmac->channel[info->chan].chcr |= CHCR_DE;
+	int irq = get_dmte_irq(info->chan);
+
+	sh_dmac->channel[info->chan].chcr |= (CHCR_DE | CHCR_IE);
+	enable_irq(irq);
 }
 
 static void sh_dmac_disable_dma(struct dma_info *info)
 {
-	sh_dmac->channel[info->chan].chcr &= ~(CHCR_DE | CHCR_TE);
+	int irq = get_dmte_irq(info->chan);
+
+	disable_irq(irq);
+	sh_dmac->channel[info->chan].chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
 }
 
 static int sh_dmac_xfer_dma(struct dma_info *info)
@@ -191,10 +172,14 @@
 	 * In this case, only one address can be defined, anything else will
 	 * result in a DMA address error interrupt (at least on the SH-4),
 	 * which will subsequently halt the transfer.
+	 *
+	 * Channel 2 on the Dreamcast is a special case, as this is used for
+	 * cascading to the PVR2 DMAC. In this case, we still need to write
+	 * SAR and DAR, regardless of value, in order for cascading to work.
 	 */
-	if (info->sar)
+	if (info->sar || (mach_is_dreamcast() && info->chan == 2))
 		sh_dmac->channel[info->chan].sar = info->sar;
-	if (info->dar)
+	if (info->dar || (mach_is_dreamcast() && info->chan == 2))
 		sh_dmac->channel[info->chan].dar = info->dar;
 	
 	sh_dmac->channel[info->chan].dmatcr = info->count >> calc_xmit_shift(info);
@@ -206,6 +191,9 @@
 
 static int sh_dmac_get_dma_residue(struct dma_info *info)
 {
+	if (!(sh_dmac->channel[info->chan].chcr & CHCR_DE))
+		return 0;
+
 	return sh_dmac->channel[info->chan].dmatcr << calc_xmit_shift(info);
 }
 
@@ -221,12 +209,6 @@
 
 	return IRQ_HANDLED;
 }
-
-static struct irqaction irq_err = {
-	.name		= "DMAC Address Error",
-	.handler	= dma_err,
-	.flags		= SA_INTERRUPT,
-};
 #endif
 
 static struct dma_ops sh_dmac_ops = {
@@ -244,15 +226,21 @@
 
 #ifdef CONFIG_CPU_SH4
 	make_ipr_irq(DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
-	setup_irq(DMAE_IRQ, &irq_err);
+	i = request_irq(DMAE_IRQ, dma_err, SA_INTERRUPT, "DMAC Address Error", 0);
+	if (i < 0)
+		return i;
 #endif
 
-	/* Kick the DMAOR */
-	sh_dmac->dmaor |= DMAOR_DME /* | 0x200 */ | 0x8000;	/* DDT = 1, PR1 = 1, DME = 1 */
-	sh_dmac->dmaor &= ~(DMAOR_NMIF | DMAOR_AE);
+	for (i = 0; i < MAX_DMAC_CHANNELS; i++) {
+		int irq = get_dmte_irq(i);
+
+		make_ipr_irq(irq, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+
+		dma_info[i].ops = &sh_dmac_ops;
+		dma_info[i].tei_capable = 1;
+	}
 
-	for (i = 0; i < MAX_DMAC_CHANNELS; i++)
-		dma_info[i].ops  = &sh_dmac_ops;
+	sh_dmac->dmaor |= 0x8000 | DMAOR_DME;
 
 	return register_dmac(&sh_dmac_ops);
 }
diff -Nru a/arch/sh/drivers/dma/dma-sh.h b/arch/sh/drivers/dma/dma-sh.h
--- a/arch/sh/drivers/dma/dma-sh.h	Sat Apr  3 19:38:54 2004
+++ b/arch/sh/drivers/dma/dma-sh.h	Sat Apr  3 19:38:54 2004
@@ -24,7 +24,6 @@
 #define DM_DEC	0x00008000
 #define SM_INC	0x00001000
 #define SM_DEC	0x00002000
-#define RS_DUAL	0x00000000
 #define RS_IN	0x00000200
 #define RS_OUT	0x00000300
 #define TM_BURST 0x0000080
@@ -36,6 +35,11 @@
 #define CHCR_DE 0x00000001
 #define CHCR_TE 0x00000002
 #define CHCR_IE 0x00000004
+
+/* Define the default configuration for dual address memory-memory transfer.
+ * The 0x400 value represents auto-request, external->external.
+ */
+#define RS_DUAL	(DM_INC | SM_INC | 0x400 | TS_32)
 
 #define DMAOR_COD	0x00000008
 #define DMAOR_AE	0x00000004
diff -Nru a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
--- a/arch/sh/drivers/pci/Kconfig	Sat Apr  3 19:38:40 2004
+++ b/arch/sh/drivers/pci/Kconfig	Sat Apr  3 19:38:40 2004
@@ -14,6 +14,7 @@
 config SH_PCIDMA_NONCOHERENT
 	bool "Cache and PCI noncoherent"
 	depends on PCI
+	default y
 	help
 	  Enable this option if your platform does not have a CPU cache which
 	  remains coherent with PCI DMA. It is safest to say 'Y', although you
@@ -38,9 +39,4 @@
 	  for some reason, you have a board that simply refuses to work
 	  with its resources updated beyond what they are when the device
 	  is powered up, set this to N. Everyone else will want this as Y.
-
-config PCI_DMA
-	bool
-	depends on PCI
-	default y if !SH_DREAMCAST
 
diff -Nru a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
--- a/arch/sh/drivers/pci/Makefile	Sat Apr  3 19:38:43 2004
+++ b/arch/sh/drivers/pci/Makefile	Sat Apr  3 19:38:43 2004
@@ -4,7 +4,6 @@
 
 obj-y					+= pci.o
 obj-$(CONFIG_PCI_AUTO)			+= pci-auto.o
-obj-$(CONFIG_PCI_DMA)			+= pci-dma.o
 
 obj-$(CONFIG_CPU_SUBTYPE_ST40STB1)	+= pci-st40.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7751)	+= pci-sh7751.o 
diff -Nru a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c
--- a/arch/sh/drivers/pci/dma-dreamcast.c	Sat Apr  3 19:38:56 2004
+++ b/arch/sh/drivers/pci/dma-dreamcast.c	Sat Apr  3 19:38:56 2004
@@ -30,7 +30,7 @@
 
 static int gapspci_dma_used = 0;
 
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+void *__pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 			   dma_addr_t * dma_handle)
 {
 	unsigned long buf;
@@ -52,7 +52,7 @@
 	return (void *)buf;
 }
 
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+void __pci_free_consistent(struct pci_dev *hwdev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
 	/* XXX */
diff -Nru a/arch/sh/drivers/pci/pci-dma.c b/arch/sh/drivers/pci/pci-dma.c
--- a/arch/sh/drivers/pci/pci-dma.c	Sat Apr  3 19:38:54 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,42 +0,0 @@
-/* 
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.                            
- *
- * Dynamic DMA mapping support.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-			   dma_addr_t * dma_handle)
-{
-	void *ret;
-	int gfp = GFP_ATOMIC;
-
-	ret = (void *) __get_free_pages(gfp, get_order(size));
-
-	if (ret != NULL) {
-	        /* Is it necessary to do the memset? */
-		memset(ret, 0, size);
-		*dma_handle = virt_to_phys(ret);
-	}
-	/* We must flush the cache before we pass it on to the device */
-	dma_cache_wback_inv(ret, size);
-	return  P2SEGADDR(ret);
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-			 void *vaddr, dma_addr_t dma_handle)
-{
-        unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
-
-	free_pages(p1addr, get_order(size));
-}
diff -Nru a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
--- a/arch/sh/kernel/cf-enabler.c	Sat Apr  3 19:38:45 2004
+++ b/arch/sh/kernel/cf-enabler.c	Sat Apr  3 19:38:45 2004
@@ -1,4 +1,4 @@
-/* $Id: cf-enabler.c,v 1.3 2003/05/04 19:29:52 lethal Exp $
+/* $Id: cf-enabler.c,v 1.4 2004/02/22 22:44:36 kkojima Exp $
  *
  *  linux/drivers/block/cf-enabler.c
  *
@@ -88,7 +88,7 @@
 }
 
 #if defined(CONFIG_SH_SOLUTION_ENGINE)
-#include <asm/hitachi_se.h>
+#include <asm/se/se.h>
 
 /*
  * SolutionEngine
diff -Nru a/arch/sh/kernel/cpu/irq_ipr.c b/arch/sh/kernel/cpu/irq_ipr.c
--- a/arch/sh/kernel/cpu/irq_ipr.c	Sat Apr  3 19:38:42 2004
+++ b/arch/sh/kernel/cpu/irq_ipr.c	Sat Apr  3 19:38:42 2004
@@ -196,6 +196,7 @@
 #endif
 
 	make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
+	make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY);
 	make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
 
 #ifdef SCI_ERI_IRQ
diff -Nru a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
--- a/arch/sh/kernel/cpu/sh4/sq.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sh/kernel/cpu/sh4/sq.c	Sat Apr  3 19:38:43 2004
@@ -3,13 +3,13 @@
  *
  * General management API for SH-4 integrated Store Queues
  *
- * Copyright (C) 2001, 2002, 2003  Paul Mundt
+ * Copyright (C) 2001, 2002, 2003, 2004  Paul Mundt
  * Copyright (C) 2001, 2002  M. R. Brown
  *
  * Some of this code has been adopted directly from the old arch/sh/mm/sq.c
- * hack that was part of the LinuxDC project. For all intensive purposes, this
- * is a completely new interface that really doesn't have much in common with
- * the old zone-based approach at all. Infact, I'm only listing it here for
+ * hack that was part of the LinuxDC project. For all intents and purposes,
+ * this is a completely new interface that really doesn't have much in common
+ * with the old zone-based approach at all. In fact, it's only listed here for
  * general completeness.
  *
  * This file is subject to the terms and conditions of the GNU General Public
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/proc_fs.h>
 #include <linux/miscdevice.h>
+#include <linux/vmalloc.h>
 
 #include <asm/io.h>
 #include <asm/page.h>
@@ -31,6 +32,9 @@
 #include <asm/cpu/sq.h>
 
 static LIST_HEAD(sq_mapping_list);
+static spinlock_t sq_mapping_lock = SPIN_LOCK_UNLOCKED;
+
+extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end);
 
 /**
  * sq_flush - Flush (prefetch) the store queue cache
@@ -42,7 +46,7 @@
  */
 inline void sq_flush(void *addr)
 {
-	__asm__ __volatile__ ("pref @%0": "=r" (addr) : : "memory");
+	__asm__ __volatile__ ("pref @%0" : : "r" (addr) : "memory");
 }
 
 /**
@@ -57,13 +61,17 @@
 void sq_flush_range(unsigned long start, unsigned int len)
 {
 	volatile unsigned long *sq = (unsigned long *)start;
+	unsigned long dummy;
 
 	/* Flush the queues */
 	for (len >>= 5; len--; sq += 8)
 		sq_flush((void *)sq);
-	
+
 	/* Wait for completion */
-	sq = (volatile unsigned long *)start;
+	dummy = ctrl_inl(P4SEG_STORE_QUE);
+
+	ctrl_outl(0, P4SEG_STORE_QUE + 0);
+	ctrl_outl(0, P4SEG_STORE_QUE + 8);
 }
 
 static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name)
@@ -81,7 +89,7 @@
 
 	map->sq_addr	= virt;
 	map->addr	= phys;
-	map->size	= size;
+	map->size	= size + 1;
 	map->name	= name;
 
 	list_add(&map->list, &sq_mapping_list);
@@ -128,24 +136,20 @@
  */
 static struct sq_mapping *__sq_remap(struct sq_mapping *map)
 {
-	/*
-	 * First check the MMU status..
-	 */
-#ifndef CONFIG_MMU
+	unsigned long flags, pteh, ptel;
+	struct vm_struct *vma;
+	pgprot_t pgprot;
+
 	/*
 	 * Without an MMU (or with it turned off), this is much more
 	 * straightforward, as we can just load up each queue's QACR with
 	 * the physical address appropriately masked.
 	 */
+
 	ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
 	ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
-#else
-	unsigned long flags, pteh, ptel;
-	pgprot_t pgprot;
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
 
+#ifdef CONFIG_MMU
 	/*
 	 * With an MMU on the other hand, things are slightly more involved.
 	 * Namely, we have to have a direct mapping between the SQ addr and
@@ -161,7 +165,7 @@
 	 * We could also probably get by without explicitly setting PTEA, but
 	 * we do it here just for good measure.
 	 */
-	local_irq_save(flags);
+	spin_lock_irqsave(&sq_mapping_lock, flags);
 
 	pteh = map->sq_addr;
 	ctrl_outl((pteh & MMU_VPN_MASK) | get_asid(), MMU_PTEH);
@@ -177,6 +181,8 @@
 
 	__asm__ __volatile__ ("ldtlb" : : : "memory");
 
+	spin_unlock_irqrestore(&sq_mapping_lock, flags);
+
 	/*
 	 * Next, we need to map ourselves in the kernel page table, so that
 	 * future accesses after a TLB flush will be handled when we take a
@@ -188,31 +194,17 @@
 	 * writeout before we hit the TLB flush, we do it anyways. This way
 	 * we at least save ourselves the initial page fault overhead.
 	 */
-	pgd = pgd_offset_k(map->sq_addr);
+	vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX);
+	if (!vma)
+		return ERR_PTR(-ENOMEM);
 
-	spin_lock(&init_mm.page_table_lock);
+	vma->phys_addr = map->addr;
 
-	pmd = pmd_alloc(&init_mm, pgd, map->sq_addr);
-	if (!pmd)
-		goto out;
-	
-	pte = pte_alloc_map(&init_mm, pmd, map->sq_addr);
-	if (!pte)
-		goto out;
-	if (!pte_none(*pte)) {
-		pte_unmap(pte);
-		goto out;
+	if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr,
+			     map->size, pgprot_val(pgprot))) {
+		vunmap(vma->addr);
+		return NULL;
 	}
-
-	set_pte(pte, mk_pte(phys_to_page(map->addr), pgprot));
-	pte_unmap(pte);
-
-out:
-	spin_unlock(&init_mm.page_table_lock);
-	sq_flush((void *)pteh);
-
-	local_irq_restore(flags);
-
 #endif /* CONFIG_MMU */
 
 	return map;
@@ -236,11 +228,20 @@
 struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name)
 {
 	struct sq_mapping *map;
-	unsigned long virt;
+	unsigned long virt, end;
 	unsigned int psz;
 
+	/* Don't allow wraparound or zero size */
+	end = phys + size - 1;
+	if (!size || end < phys)
+		return NULL;
+	/* Don't allow anyone to remap normal memory.. */
+	if (phys < virt_to_phys(high_memory))
+		return NULL;
+
 	phys &= PAGE_MASK;
 
+	size  = PAGE_ALIGN(end + 1) - phys;
 	virt  = __sq_get_next_addr();
 	psz   = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
 	map   = __sq_alloc_mapping(virt, phys, size, name);
@@ -264,30 +265,8 @@
  */
 void sq_unmap(struct sq_mapping *map)
 {
-#ifdef CONFIG_MMU
-	pgd_t *pgd;
-	pmd_t *pmd;
-	pte_t *pte;
-	
-	pgd = pgd_offset_k(map->sq_addr);
-	pmd = pmd_offset(pgd, map->sq_addr);
-
-	if (pmd_none(*pmd))
-		return;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-
-	pte = pte_offset_kernel(pmd, map->sq_addr);
-	if (pte_none(*pte) || pte_not_present(*pte))
-		return;
-
-	ptep_get_and_clear(pte);
-
-	__flush_tlb_page(get_asid(), map->sq_addr & PAGE_MASK);
-#endif
+	if (map->sq_addr > (unsigned long)high_memory)
+		vfree((void *)(map->sq_addr & PAGE_MASK));
 
 	list_del(&map->list);
 	kfree(map);
@@ -475,6 +454,7 @@
 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
 MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(STORE_QUEUE_MINOR);
 
 EXPORT_SYMBOL(sq_remap);
 EXPORT_SYMBOL(sq_unmap);
diff -Nru a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
--- a/arch/sh/kernel/entry.S	Sat Apr  3 19:38:42 2004
+++ b/arch/sh/kernel/entry.S	Sat Apr  3 19:38:42 2004
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.34 2004/01/13 05:52:11 kkojima Exp $
+/* $Id: entry.S,v 1.35 2004/02/21 14:45:47 lethal Exp $
  *
  *  linux/arch/sh/entry.S
  *
@@ -1129,9 +1129,6 @@
 	.long sys_utimes
  	.long sys_fadvise64_64_wrapper
 	.long sys_ni_syscall	/* Reserved for vserver */
-
-	.rept NR_syscalls-(.-sys_call_table)/4
-		.long sys_ni_syscall
-	.endr
+	.long sys_ni_syscall
 
 /* End of entry.S */
diff -Nru a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c
--- a/arch/sh/kernel/io.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sh/kernel/io.c	Sat Apr  3 19:38:43 2004
@@ -16,10 +16,11 @@
  */
 void  memcpy_fromio(void * to, unsigned long from, unsigned long count)
 {
+	char *p = to;
         while (count) {
                 count--;
-                *(char *) to = readb(from);
-                ((char *) to)++;
+                *p = readb(from);
+                p++;
                 from++;
         }
 }
@@ -30,10 +31,11 @@
  */
 void  memcpy_toio(unsigned long to, const void * from, unsigned long count)
 {
+	const char *p = from;
         while (count) {
                 count--;
-                writeb(*(char *) from, to);
-                ((char *) from)++;
+                writeb(*p, to);
+                p++;
                 to++;
         }
 }
diff -Nru a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
--- a/arch/sh/kernel/module.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sh/kernel/module.c	Sat Apr  3 19:38:55 2004
@@ -55,20 +55,22 @@
 #define COPY_UNALIGNED_WORD(sw, tw, align) \
 { \
 	void *__s = &(sw), *__t = &(tw); \
+	unsigned short *__s2 = __s, *__t2 = __t; \
+	unsigned char *__s1 = __s, *__t1 = __t; \
 	switch ((align)) \
 	{ \
 	case 0: \
 		*(unsigned long *) __t = *(unsigned long *) __s; \
 		break; \
 	case 2: \
-		*((unsigned short *) __t)++ = *((unsigned short *) __s)++; \
-		*((unsigned short *) __t) = *((unsigned short *) __s); \
+		*__t2++ = *__s2++; \
+		*__t2 = *__s2; \
 		break; \
 	default: \
-		*((unsigned char *) __t)++ = *((unsigned char *) __s)++; \
-		*((unsigned char *) __t)++ = *((unsigned char *) __s)++; \
-		*((unsigned char *) __t)++ = *((unsigned char *) __s)++; \
-		*((unsigned char *) __t) = *((unsigned char *) __s); \
+		*__t1++ = *__s1++; \
+		*__t1++ = *__s1++; \
+		*__t1++ = *__s1++; \
+		*__t1 = *__s1; \
 		break; \
 	} \
 }
diff -Nru a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
--- a/arch/sh/kernel/process.c	Sat Apr  3 19:38:54 2004
+++ b/arch/sh/kernel/process.c	Sat Apr  3 19:38:54 2004
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.25 2004/01/13 05:52:11 kkojima Exp $
+/* $Id: process.c,v 1.26 2004/02/06 14:14:14 kkojima Exp $
  *
  *  linux/arch/sh/kernel/process.c
  *
@@ -254,6 +254,13 @@
 		struct task_struct *p, struct pt_regs *regs)
 {
 	struct pt_regs *childregs;
+#if defined(CONFIG_CPU_SH4)
+	struct task_struct *tsk = current;
+
+	unlazy_fpu(tsk, regs);
+	p->thread.fpu = tsk->thread.fpu;
+	p->used_math = tsk->used_math;
+#endif
 
 	childregs = ((struct pt_regs *)
 		(THREAD_SIZE + (unsigned long) p->thread_info)
@@ -279,16 +286,6 @@
 
 	p->thread.ubc_pc = 0;
 
-#if defined(CONFIG_CPU_SH4)
-	{
-		struct task_struct *tsk = current;
-
-		unlazy_fpu(tsk, regs);
-		p->thread.fpu = tsk->thread.fpu;
-		p->used_math = tsk->used_math;
-		clear_ti_thread_flag(p->thread_info, TIF_USEDFPU);
-	}
-#endif
 	return 0;
 }
 
diff -Nru a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
--- a/arch/sh/kernel/sh_ksyms.c	Sat Apr  3 19:38:41 2004
+++ b/arch/sh/kernel/sh_ksyms.c	Sat Apr  3 19:38:41 2004
@@ -113,3 +113,5 @@
 #ifdef CONFIG_SMP
 EXPORT_SYMBOL(synchronize_irq);
 #endif
+
+EXPORT_SYMBOL(csum_partial);
diff -Nru a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
--- a/arch/sh/kernel/sys_sh.c	Sat Apr  3 19:38:57 2004
+++ b/arch/sh/kernel/sys_sh.c	Sat Apr  3 19:38:57 2004
@@ -44,7 +44,7 @@
 	return error;
 }
 
-#if defined(CONFIG_CPU_SH4)
+#if defined(HAVE_ARCH_UNMAPPED_AREA)
 /*
  * To avoid cache alias, we map the shard page with same color.
  */
@@ -53,7 +53,9 @@
 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
 	unsigned long len, unsigned long pgoff, unsigned long flags)
 {
+	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma;
+	unsigned long start_addr;
 
 	if (flags & MAP_FIXED) {
 		/* We do not accept a shared mapping if it would violate
@@ -66,20 +68,44 @@
 
 	if (len > TASK_SIZE)
 		return -ENOMEM;
-	if (!addr)
-		addr = TASK_UNMAPPED_BASE;
 
+	if (addr) {
+		if (flags & MAP_PRIVATE)
+			addr = PAGE_ALIGN(addr);
+		else
+			addr = COLOUR_ALIGN(addr);
+		vma = find_vma(mm, addr);
+		if (TASK_SIZE - len >= addr &&
+		    (!vma || addr + len <= vma->vm_start))
+			return addr;
+	}
 	if (flags & MAP_PRIVATE)
-		addr = PAGE_ALIGN(addr);
+		addr = PAGE_ALIGN(mm->free_area_cache);
 	else
-		addr = COLOUR_ALIGN(addr);
+		addr = COLOUR_ALIGN(mm->free_area_cache);
+	start_addr = addr;
 
-	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+full_search:
+	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
 		/* At this point:  (!vma || addr < vma->vm_end). */
-		if (TASK_SIZE - len < addr)
+		if (TASK_SIZE - len < addr) {
+			/*
+			 * Start a new search - just in case we missed
+			 * some holes.
+			 */
+			if (start_addr != TASK_UNMAPPED_BASE) {
+				start_addr = addr = TASK_UNMAPPED_BASE;
+				goto full_search;
+			}
 			return -ENOMEM;
-		if (!vma || addr + len <= vma->vm_start)
+		}
+		if (!vma || addr + len <= vma->vm_start) {
+			/*
+			 * Remember the place where we stopped the search:
+			 */
+			mm->free_area_cache = addr + len;
 			return addr;
+		}
 		addr = vma->vm_end;
 		if (!(flags & MAP_PRIVATE))
 			addr = COLOUR_ALIGN(addr);
diff -Nru a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
--- a/arch/sh/kernel/time.c	Sat Apr  3 19:38:40 2004
+++ b/arch/sh/kernel/time.c	Sat Apr  3 19:38:40 2004
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.18 2003/10/09 16:28:14 lethal Exp $
+/* $Id: time.c,v 1.19 2004/02/27 00:40:48 lethal Exp $
  *
  *  linux/arch/sh/kernel/time.c
  *
@@ -86,10 +86,14 @@
 #endif
 
 #if defined(CONFIG_CPU_SH3)
-#error "FIXME"
-static int ifc_table[] = { 1, 2, 4, 1, 3, 1, 1, 1 };
-static int pfc_table[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
-static int stc_table[] = { 1, 2, 4, 8, 3, 6, 1, 1 };
+static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 };
+static int stc_values[]      = { 0, 1, 4, 2, 5, 0, 0, 0 };
+#define bfc_divisors stc_multipliers
+#define bfc_values stc_values
+static int ifc_divisors[]    = { 1, 2, 3, 4, 1, 1, 1, 1 };
+static int ifc_values[]      = { 0, 1, 4, 2, 0, 0, 0, 0 };
+static int pfc_divisors[]    = { 1, 2, 3, 4, 6, 1, 1, 1 };
+static int pfc_values[]      = { 0, 1, 4, 2, 5, 0, 0, 0 };
 #elif defined(CONFIG_CPU_SH4)
 static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 1, 1 };
 static int ifc_values[]   = { 0, 1, 2, 3, 0, 4, 0, 5 };
@@ -398,13 +402,13 @@
 
 	tmp  = (frqcr & 0x8000) >> 13;
 	tmp |= (frqcr & 0x0030) >>  4;
-	*bfc = stc_table[tmp];
+	*bfc = stc_multipliers[tmp];
 	tmp  = (frqcr & 0x4000)  >> 12;
 	tmp |= (frqcr & 0x000c) >> 2;
-	*ifc  = ifc_table[tmp];
+	*ifc = ifc_divisors[tmp];
 	tmp  = (frqcr & 0x2000) >> 11;
 	tmp |= frqcr & 0x0003;
-	*pfc = pfc_table[tmp];
+	*pfc = pfc_divisors[tmp];
 #elif defined(CONFIG_CPU_SH4)
 	*ifc = ifc_divisors[(frqcr >> 6) & 0x0007];
 	*bfc = bfc_divisors[(frqcr >> 3) & 0x0007];
diff -Nru a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
--- a/arch/sh/kernel/traps.c	Sat Apr  3 19:38:41 2004
+++ b/arch/sh/kernel/traps.c	Sat Apr  3 19:38:41 2004
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.14 2003/11/14 18:40:10 lethal Exp $
+/* $Id: traps.c,v 1.16 2004/03/16 00:10:54 lethal Exp $
  *
  *  linux/arch/sh/traps.c
  *
@@ -655,6 +655,10 @@
 	unsigned long module_start = VMALLOC_START;
 	unsigned long module_end = VMALLOC_END;
 	int i = 1;
+
+	if (tsk && !sp) {
+		sp = (unsigned long *)tsk->thread.sp;
+	}
 
 	if (!sp) {
 		__asm__ __volatile__ (
diff -Nru a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
--- a/arch/sh/mm/Makefile	Sat Apr  3 19:38:55 2004
+++ b/arch/sh/mm/Makefile	Sat Apr  3 19:38:55 2004
@@ -2,13 +2,14 @@
 # Makefile for the Linux SuperH-specific parts of the memory manager.
 #
 
-obj-y			:= init.o extable.o
+obj-y			:= init.o extable.o consistent.o
 
 obj-$(CONFIG_CPU_SH2)	+= cache-sh2.o
 obj-$(CONFIG_CPU_SH3)	+= cache-sh3.o
 obj-$(CONFIG_CPU_SH4)	+= cache-sh4.o pg-sh4.o
 
 obj-$(CONFIG_DMA_PAGE_OPS)	+= pg-dma.o
+obj-$(CONFIG_HUGETLB_PAGE)	+= hugetlbpage.o
 
 mmu-y			:= fault-nommu.o tlb-nommu.o pg-nommu.o
 mmu-$(CONFIG_MMU)	:= fault.o clear_page.o copy_page.o
diff -Nru a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
--- a/arch/sh/mm/cache-sh4.c	Sat Apr  3 19:38:41 2004
+++ b/arch/sh/mm/cache-sh4.c	Sat Apr  3 19:38:41 2004
@@ -1,9 +1,10 @@
-/* $Id: cache-sh4.c,v 1.24 2003/10/12 19:40:12 lethal Exp $
+/* $Id: cache-sh4.c,v 1.26 2004/02/19 12:47:24 lethal Exp $
  *
  *  linux/arch/sh/mm/cache-sh4.c
  *
  * Copyright (C) 1999, 2000, 2002  Niibe Yutaka
- * Copyright (C) 2001, 2002, 2003  Paul Mundt
+ * Copyright (C) 2001, 2002, 2003, 2004  Paul Mundt
+ * Copyright (C) 2003  Richard Curnow
  */
 
 #include <linux/config.h>
@@ -29,10 +30,20 @@
 
 int __init detect_cpu_and_cache_system(void)
 {
-	unsigned long pvr, prr, ccr;
+	unsigned long pvr, prr, ccr, cvr;
+	unsigned long size;
+
+	static unsigned long sizes[16] = {
+		[1] = (1 << 12),
+		[2] = (1 << 13),
+		[4] = (1 << 14),
+		[8] = (1 << 15),
+		[9] = (1 << 16)
+	};
 
 	pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff;
 	prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
+	cvr = (ctrl_inl(CCN_CVR));
 
 	/*
 	 * Setup some sane SH-4 defaults for the icache
@@ -54,6 +65,9 @@
 	cpu_data->dcache.ways		= 1;
 	cpu_data->dcache.linesz		= L1_CACHE_BYTES;
 
+	/* Set the FPU flag, virtually all SH-4's have one */
+	set_bit(CPU_HAS_FPU, &(cpu_data->flags));
+
 	/*
 	 * Probe the underlying processor version/revision and
 	 * adjust cpu_data setup accordingly.
@@ -68,7 +82,7 @@
 
 		/* 
 		 * FIXME: This is needed for 7750, but do we need it for the
-		 * 7750S and 7750R too? For now, assume we do.. -- PFM
+		 * 7750S too? For now, assume we do.. -- PFM
 		 */
 		set_bit(CPU_HAS_P2_FLUSH_BUG, &(cpu_data->flags));
 
@@ -83,12 +97,18 @@
 		cpu_data->type = CPU_ST40GX1;
 		break;
 	case 0x700:
-		/* XXX: Add proper CVR probing */
 		cpu_data->type = CPU_SH4_501;
+		cpu_data->icache.ways = 2;
+		cpu_data->dcache.ways = 2;
+
+		/* No FPU on the SH4-500 series.. */
+		clear_bit(CPU_HAS_FPU, &(cpu_data->flags));
 		break;
 	case 0x600:
 		cpu_data->type = CPU_SH4_202;
-		/* fall */
+		cpu_data->icache.ways = 2;
+		cpu_data->dcache.ways = 2;
+		break;
 	case 0x500 ... 0x501:
 		switch (prr) {
 		    case 0x10: cpu_data->type = CPU_SH7750R; break;
@@ -96,9 +116,20 @@
 		    case 0x50: cpu_data->type = CPU_SH7760;  break;
 		}
 
-		if (cpu_data->type == CPU_SH7750R)
-			set_bit(CPU_HAS_P2_FLUSH_BUG, &(cpu_data->flags));
+		cpu_data->icache.ways = 2;
+		cpu_data->dcache.ways = 2;
+
+		break;
+	default:
+		cpu_data->type = CPU_SH_NONE;
+		break;
+	}
 
+	/*
+	 * On anything that's not a direct-mapped cache, look to the CVR
+	 * for I/D-cache specifics.
+	 */
+	if (cpu_data->dcache.ways > 1) {
 		jump_to_P2();
 		ccr = ctrl_inl(CCR);
 
@@ -110,19 +141,17 @@
 
 		back_to_P1();
 
-		cpu_data->icache.ways = 2;
-		cpu_data->dcache.ways = 2;
-
-		break;
-	default:
-		cpu_data->type = CPU_SH_NONE;
-		break;
+		size = sizes[(cvr >> 20) & 0xf];
+		cpu_data->icache.way_shift	=  (size >> 1);
+		cpu_data->icache.entry_mask	= ((size >> 2) - (1 << 5));
+		cpu_data->icache.sets		=  (size >> 6);
+
+		size = sizes[(cvr >> 16) & 0xf];
+		cpu_data->dcache.way_shift	=  (size >> 1);
+		cpu_data->dcache.entry_mask	= ((size >> 2) - (1 << 5));
+		cpu_data->dcache.sets		=  (size >> 6);
 	}
 
-	/* No FPU on the SH4-500 series.. */
-	if (cpu_data->type != CPU_SH4_501)
-		set_bit(CPU_HAS_FPU, &(cpu_data->flags));
-
 	return 0;
 }
 
@@ -419,7 +448,7 @@
 			}
 			pte++;
 			p += PAGE_SIZE;
-		} while (p < end && (unsigned long)pte & PAGE_MASK);
+		} while (p < end && ((unsigned long)pte & ~PAGE_MASK));
 		pmd++;
 	} while (p < end);
  loop_exit:
diff -Nru a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/mm/consistent.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,79 @@
+/*
+ * arch/sh/mm/consistent.c
+ *
+ * Copyright (C) 2004  Paul Mundt
+ *
+ * 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.
+ */
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle)
+{
+	struct page *page, *end, *free;
+	void *ret;
+	int order;
+
+	size = PAGE_ALIGN(size);
+	order = get_order(size);
+
+	page = alloc_pages(gfp, order);
+	if (!page)
+		return NULL;
+
+	ret = (void *)P2SEGADDR(page_to_bus(page));
+
+	/*
+	 * We must flush the cache before we pass it on to the device
+	 */
+	dma_cache_wback_inv(ret, size);
+
+	*handle = (unsigned long)ret;
+
+	free = page + (size >> PAGE_SHIFT);
+	end  = page + (1 << order);
+
+	do {
+		set_page_count(page, 1);
+		page++;
+	} while (size -= PAGE_SIZE);
+
+	/*
+	 * Free any unused pages
+	 */
+	while (page < end) {
+		set_page_count(page, 1);
+		__free_page(page);
+		page++;
+	}
+
+	return ret;
+}
+
+void consistent_free(void *vaddr, size_t size)
+{
+	unsigned long addr = P1SEGADDR((unsigned long)vaddr);
+
+	free_pages(addr, get_order(size));
+}
+
+void consistent_sync(void *vaddr, size_t size, int direction)
+{
+	switch (direction) {
+	case DMA_FROM_DEVICE:		/* invalidate only */
+		dma_cache_inv(vaddr, size);
+		break;
+	case DMA_TO_DEVICE:		/* writeback only */
+		dma_cache_wback(vaddr, size);
+		break;
+	case DMA_BIDIRECTIONAL:		/* writeback and invalidate */
+		dma_cache_wback_inv(vaddr, size);
+		break;
+	default:
+		BUG();
+	}
+}
+
diff -Nru a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sh/mm/hugetlbpage.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,526 @@
+/*
+ * arch/sh/mm/hugetlbpage.c
+ *
+ * SuperH HugeTLB page support.
+ *
+ * Cloned from sparc64 by Paul Mundt.
+ *
+ * Copyright (C) 2002, 2003 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+
+#include <asm/mman.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+
+static long	htlbpagemem;
+int		htlbpage_max;
+static long	htlbzone_pages;
+
+static struct list_head hugepage_freelists[MAX_NUMNODES];
+static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED;
+
+static void enqueue_huge_page(struct page *page)
+{
+	list_add(&page->list,
+		 &hugepage_freelists[page_zone(page)->zone_pgdat->node_id]);
+}
+
+static struct page *dequeue_huge_page(void)
+{
+	int nid = numa_node_id();
+	struct page *page = NULL;
+
+	if (list_empty(&hugepage_freelists[nid])) {
+		for (nid = 0; nid < MAX_NUMNODES; ++nid)
+			if (!list_empty(&hugepage_freelists[nid]))
+				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);
+	}
+	return page;
+}
+
+static struct page *alloc_fresh_huge_page(void)
+{
+	static int nid = 0;
+	struct page *page;
+	page = alloc_pages_node(nid, GFP_HIGHUSER, HUGETLB_PAGE_ORDER);
+	nid = (nid + 1) % numnodes;
+	return page;
+}
+
+static void free_huge_page(struct page *page);
+
+static struct page *alloc_hugetlb_page(void)
+{
+	struct page *page;
+
+	spin_lock(&htlbpage_lock);
+	page = dequeue_huge_page();
+	if (!page) {
+		spin_unlock(&htlbpage_lock);
+		return NULL;
+	}
+	htlbpagemem--;
+	spin_unlock(&htlbpage_lock);
+	set_page_count(page, 1);
+	page->lru.prev = (void *)free_huge_page;
+	memset(page_address(page), 0, HPAGE_SIZE);
+	return page;
+}
+
+static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte = NULL;
+
+	pgd = pgd_offset(mm, addr);
+	if (pgd) {
+		pmd = pmd_alloc(mm, pgd, addr);
+		if (pmd)
+			pte = pte_alloc_map(mm, pmd, addr);
+	}
+	return pte;
+}
+
+static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte = NULL;
+
+	pgd = pgd_offset(mm, addr);
+	if (pgd) {
+		pmd = pmd_offset(pgd, addr);
+		if (pmd)
+			pte = pte_offset_map(pmd, addr);
+	}
+	return pte;
+}
+
+#define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZHUGE; } while (0)
+
+static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+			 struct page *page, pte_t * page_table, int write_access)
+{
+	unsigned long i;
+	pte_t entry;
+
+	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+
+	if (write_access)
+		entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
+						       vma->vm_page_prot)));
+	else
+		entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
+	entry = pte_mkyoung(entry);
+	mk_pte_huge(entry);
+
+	for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+		set_pte(page_table, entry);
+		page_table++;
+
+		pte_val(entry) += PAGE_SIZE;
+	}
+}
+
+/*
+ * This function checks for proper alignment of input addr and len parameters.
+ */
+int is_aligned_hugepage_range(unsigned long addr, unsigned long len)
+{
+	if (len & ~HPAGE_MASK)
+		return -EINVAL;
+	if (addr & ~HPAGE_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+			    struct vm_area_struct *vma)
+{
+	pte_t *src_pte, *dst_pte, entry;
+	struct page *ptepage;
+	unsigned long addr = vma->vm_start;
+	unsigned long end = vma->vm_end;
+	int i;
+
+	while (addr < end) {
+		dst_pte = huge_pte_alloc(dst, addr);
+		if (!dst_pte)
+			goto nomem;
+		src_pte = huge_pte_offset(src, addr);
+		BUG_ON(!src_pte || pte_none(*src_pte));
+		entry = *src_pte;
+		ptepage = pte_page(entry);
+		get_page(ptepage);
+		for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+			set_pte(dst_pte, entry);
+			pte_val(entry) += PAGE_SIZE;
+			dst_pte++;
+		}
+		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+		addr += HPAGE_SIZE;
+	}
+	return 0;
+
+nomem:
+	return -ENOMEM;
+}
+
+int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
+			struct page **pages, struct vm_area_struct **vmas,
+			unsigned long *position, int *length, int i)
+{
+	unsigned long vaddr = *position;
+	int remainder = *length;
+
+	WARN_ON(!is_vm_hugetlb_page(vma));
+
+	while (vaddr < vma->vm_end && remainder) {
+		if (pages) {
+			pte_t *pte;
+			struct page *page;
+
+			pte = huge_pte_offset(mm, vaddr);
+
+			/* hugetlb should be locked, and hence, prefaulted */
+			BUG_ON(!pte || pte_none(*pte));
+
+			page = pte_page(*pte);
+
+			WARN_ON(!PageCompound(page));
+
+			get_page(page);
+			pages[i] = page;
+		}
+
+		if (vmas)
+			vmas[i] = vma;
+
+		vaddr += PAGE_SIZE;
+		--remainder;
+		++i;
+	}
+
+	*length = remainder;
+	*position = vaddr;
+
+	return i;
+}
+
+struct page *follow_huge_addr(struct mm_struct *mm,
+			      struct vm_area_struct *vma,
+			      unsigned long address, int write)
+{
+	return NULL;
+}
+
+struct vm_area_struct *hugepage_vma(struct mm_struct *mm, unsigned long addr)
+{
+	return NULL;
+}
+
+int pmd_huge(pmd_t pmd)
+{
+	return 0;
+}
+
+struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+			     pmd_t *pmd, int write)
+{
+	return NULL;
+}
+
+static void free_huge_page(struct page *page)
+{
+	BUG_ON(page_count(page));
+	BUG_ON(page->mapping);
+
+	INIT_LIST_HEAD(&page->list);
+
+	spin_lock(&htlbpage_lock);
+	enqueue_huge_page(page);
+	htlbpagemem++;
+	spin_unlock(&htlbpage_lock);
+}
+
+void huge_page_release(struct page *page)
+{
+	if (!put_page_testzero(page))
+		return;
+
+	free_huge_page(page);
+}
+
+void unmap_hugepage_range(struct vm_area_struct *vma,
+			  unsigned long start, unsigned long end)
+{
+	struct mm_struct *mm = vma->vm_mm;
+	unsigned long address;
+	pte_t *pte;
+	struct page *page;
+	int i;
+
+	BUG_ON(start & (HPAGE_SIZE - 1));
+	BUG_ON(end & (HPAGE_SIZE - 1));
+
+	for (address = start; address < end; address += HPAGE_SIZE) {
+		pte = huge_pte_offset(mm, address);
+		BUG_ON(!pte);
+		if (pte_none(*pte))
+			continue;
+		page = pte_page(*pte);
+		huge_page_release(page);
+		for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+			pte_clear(pte);
+			pte++;
+		}
+	}
+	mm->rss -= (end - start) >> PAGE_SHIFT;
+	flush_tlb_range(vma, start, end);
+}
+
+void zap_hugepage_range(struct vm_area_struct *vma,
+			unsigned long start, unsigned long length)
+{
+	struct mm_struct *mm = vma->vm_mm;
+
+	spin_lock(&mm->page_table_lock);
+	unmap_hugepage_range(vma, start, start + length);
+	spin_unlock(&mm->page_table_lock);
+}
+
+int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long addr;
+	int ret = 0;
+
+	BUG_ON(vma->vm_start & ~HPAGE_MASK);
+	BUG_ON(vma->vm_end & ~HPAGE_MASK);
+
+	spin_lock(&mm->page_table_lock);
+	for (addr = vma->vm_start; addr < vma->vm_end; addr += HPAGE_SIZE) {
+		unsigned long idx;
+		pte_t *pte = huge_pte_alloc(mm, addr);
+		struct page *page;
+
+		if (!pte) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		if (!pte_none(*pte))
+			continue;
+
+		idx = ((addr - vma->vm_start) >> HPAGE_SHIFT)
+			+ (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
+		page = find_get_page(mapping, idx);
+		if (!page) {
+			/* charge the fs quota first */
+			if (hugetlb_get_quota(mapping)) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			page = alloc_hugetlb_page();
+			if (!page) {
+				hugetlb_put_quota(mapping);
+				ret = -ENOMEM;
+				goto out;
+			}
+			ret = add_to_page_cache(page, mapping, idx, GFP_ATOMIC);
+			unlock_page(page);
+			if (ret) {
+				hugetlb_put_quota(mapping);
+				free_huge_page(page);
+				goto out;
+			}
+		}
+		set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
+	}
+out:
+	spin_unlock(&mm->page_table_lock);
+	return ret;
+}
+
+static void update_and_free_page(struct page *page)
+{
+	int j;
+	struct page *map;
+
+	map = page;
+	htlbzone_pages--;
+	for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
+		map->flags &= ~(1 << PG_locked | 1 << PG_error | 1 << PG_referenced |
+				1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
+				1 << PG_private | 1<< PG_writeback);
+		set_page_count(map, 0);
+		map++;
+	}
+	set_page_count(page, 1);
+	__free_pages(page, HUGETLB_PAGE_ORDER);
+}
+
+static int try_to_free_low(int count)
+{
+	struct list_head *p;
+	struct page *page, *map;
+
+	map = NULL;
+	spin_lock(&htlbpage_lock);
+	/* all lowmem is on node 0 */
+	list_for_each(p, &hugepage_freelists[0]) {
+		if (map) {
+			list_del(&map->list);
+			update_and_free_page(map);
+			htlbpagemem--;
+			map = NULL;
+			if (++count == 0)
+				break;
+		}
+		page = list_entry(p, struct page, list);
+		if (!PageHighMem(page))
+			map = page;
+	}
+	if (map) {
+		list_del(&map->list);
+		update_and_free_page(map);
+		htlbpagemem--;
+		count++;
+	}
+	spin_unlock(&htlbpage_lock);
+	return count;
+}
+
+static int set_hugetlb_mem_size(int count)
+{
+	int lcount;
+	struct page *page;
+
+	if (count < 0)
+		lcount = count;
+	else
+		lcount = count - htlbzone_pages;
+
+	if (lcount == 0)
+		return (int)htlbzone_pages;
+	if (lcount > 0) {	/* Increase the mem size. */
+		while (lcount--) {
+			page = alloc_fresh_huge_page();
+			if (page == NULL)
+				break;
+			spin_lock(&htlbpage_lock);
+			enqueue_huge_page(page);
+			htlbpagemem++;
+			htlbzone_pages++;
+			spin_unlock(&htlbpage_lock);
+		}
+		return (int) htlbzone_pages;
+	}
+	/* Shrink the memory size. */
+	lcount = try_to_free_low(lcount);
+	while (lcount++) {
+		page = alloc_hugetlb_page();
+		if (page == NULL)
+			break;
+		spin_lock(&htlbpage_lock);
+		update_and_free_page(page);
+		spin_unlock(&htlbpage_lock);
+	}
+	return (int) htlbzone_pages;
+}
+
+int hugetlb_sysctl_handler(struct ctl_table *table, int write,
+			   struct file *file, void *buffer, size_t *length)
+{
+	proc_dointvec(table, write, file, buffer, length);
+	htlbpage_max = set_hugetlb_mem_size(htlbpage_max);
+	return 0;
+}
+
+static int __init hugetlb_setup(char *s)
+{
+	if (sscanf(s, "%d", &htlbpage_max) <= 0)
+		htlbpage_max = 0;
+	return 1;
+}
+__setup("hugepages=", hugetlb_setup);
+
+static int __init hugetlb_init(void)
+{
+	int i;
+	struct page *page;
+
+	for (i = 0; i < MAX_NUMNODES; ++i)
+		INIT_LIST_HEAD(&hugepage_freelists[i]);
+
+	for (i = 0; i < htlbpage_max; ++i) {
+		page = alloc_fresh_huge_page();
+		if (!page)
+			break;
+		spin_lock(&htlbpage_lock);
+		enqueue_huge_page(page);
+		spin_unlock(&htlbpage_lock);
+	}
+	htlbpage_max = htlbpagemem = htlbzone_pages = i;
+	printk("Total HugeTLB memory allocated, %ld\n", htlbpagemem);
+	return 0;
+}
+module_init(hugetlb_init);
+
+int hugetlb_report_meminfo(char *buf)
+{
+	return sprintf(buf,
+			"HugePages_Total: %5lu\n"
+			"HugePages_Free:  %5lu\n"
+			"Hugepagesize:    %5lu kB\n",
+			htlbzone_pages,
+			htlbpagemem,
+			HPAGE_SIZE/1024);
+}
+
+int is_hugepage_mem_enough(size_t size)
+{
+	return (size + ~HPAGE_MASK)/HPAGE_SIZE <= htlbpagemem;
+}
+
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+	return htlbzone_pages * (HPAGE_SIZE / PAGE_SIZE);
+}
+EXPORT_SYMBOL(hugetlb_total_pages);
+
+/*
+ * We cannot handle pagefaults against hugetlb pages at all.  They cause
+ * handle_mm_fault() to try to instantiate regular-sized pages in the
+ * hugegpage VMA.  do_page_fault() is supposed to trap this, so BUG is we get
+ * this far.
+ */
+static struct page *hugetlb_nopage(struct vm_area_struct *vma,
+				   unsigned long address, int *unused)
+{
+	BUG();
+	return NULL;
+}
+
+struct vm_operations_struct hugetlb_vm_ops = {
+	.nopage = hugetlb_nopage,
+};
diff -Nru a/arch/sh/mm/init.c b/arch/sh/mm/init.c
--- a/arch/sh/mm/init.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sh/mm/init.c	Sat Apr  3 19:38:55 2004
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.18 2003/10/31 09:26:59 kkojima Exp $
+/* $Id: init.c,v 1.19 2004/02/21 04:42:16 kkojima Exp $
  *
  *  linux/arch/sh/mm/init.c
  *
@@ -174,6 +174,7 @@
 	extern unsigned long empty_zero_page[1024];
 	int codesize, reservedpages, datasize, initsize;
 	int tmp;
+	extern unsigned long memory_start;
 
 #ifdef CONFIG_MMU
 	high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE);
@@ -183,7 +184,7 @@
 	high_memory = (void *)(memory_end & PAGE_MASK);
 #endif
 
-	max_mapnr = num_physpages = MAP_NR(high_memory);
+	max_mapnr = num_physpages = MAP_NR(high_memory) - MAP_NR(memory_start);
 
 	/* clear the zero-page */
 	memset(empty_zero_page, 0, PAGE_SIZE);
diff -Nru a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c
--- a/arch/sh/mm/ioremap.c	Sat Apr  3 19:38:44 2004
+++ b/arch/sh/mm/ioremap.c	Sat Apr  3 19:38:44 2004
@@ -1,4 +1,4 @@
-/* $Id: ioremap.c,v 1.8 2003/10/09 15:25:42 lethal Exp $
+/* $Id: ioremap.c,v 1.9 2004/02/25 04:59:10 lethal Exp $
  *
  * arch/sh/mm/ioremap.c
  *
@@ -160,5 +160,5 @@
 void p3_iounmap(void *addr)
 {
 	if (addr > high_memory)
-		return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+		vfree((void *)(PAGE_MASK & (unsigned long)addr));
 }
diff -Nru a/arch/sh/mm/pg-dma.c b/arch/sh/mm/pg-dma.c
--- a/arch/sh/mm/pg-dma.c	Sat Apr  3 19:38:44 2004
+++ b/arch/sh/mm/pg-dma.c	Sat Apr  3 19:38:44 2004
@@ -21,7 +21,7 @@
 #include <asm/io.h>
 
 /* Channel to use for page ops, must be dual-address mode capable. */
-static int dma_channel = 3;
+static int dma_channel = CONFIG_DMA_PAGE_OPS_CHANNEL;
 
 static void copy_page_dma(void *to, void *from)
 {
diff -Nru a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c
--- a/arch/sh/mm/tlb-sh4.c	Sat Apr  3 19:38:45 2004
+++ b/arch/sh/mm/tlb-sh4.c	Sat Apr  3 19:38:45 2004
@@ -68,7 +68,7 @@
 	/* Set PTEL register */
 	pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
 #ifdef CONFIG_SH_WRITETHROUGH
-	pteval |= 1;
+	pteval |= _PAGE_WT;
 #endif
 	/* conveniently, we want all the software flags to be 0 anyway */
 	ctrl_outl(pteval, MMU_PTEL);
diff -Nru a/arch/sparc/Kconfig b/arch/sparc/Kconfig
--- a/arch/sparc/Kconfig	Sat Apr  3 19:38:31 2004
+++ b/arch/sparc/Kconfig	Sat Apr  3 19:38:31 2004
@@ -103,8 +103,8 @@
 	  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
 	  Management" code will be disabled if you say Y here.
 
-	  See also the <file:Documentation/smp.tex>,
-	  <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
+	  See also the <file:Documentation/smp.txt>,
+	  <file:Documentation/i386/IO-APIC.txt>,
 	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
 	  <http://www.tldp.org/docs.html#howto>.
 
diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile
--- a/arch/sparc/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/sparc/Makefile	Sat Apr  3 19:38:41 2004
@@ -67,7 +67,8 @@
 	$(call filechk,gen-asm-offsets)
 
 CLEAN_FILES +=	include/asm-$(ARCH)/asm_offsets.h	\
-		arch/$(ARCH)/kernel/asm-offsets.s
+		arch/$(ARCH)/kernel/asm-offsets.s	\
+		arch/$(ARCH)/boot/System.map
 
 # Don't use tabs in echo arguments.
 define archhelp
diff -Nru a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
--- a/arch/sparc/boot/Makefile	Sat Apr  3 19:38:55 2004
+++ b/arch/sparc/boot/Makefile	Sat Apr  3 19:38:55 2004
@@ -32,6 +32,3 @@
 
 $(obj)/btfix.s: $(obj)/btfixupprep vmlinux FORCE
 	$(call if_changed,btfix)
-
-clean:
-	rm $(obj)/System.map
diff -Nru a/arch/sparc/defconfig b/arch/sparc/defconfig
--- a/arch/sparc/defconfig	Sat Apr  3 19:38:54 2004
+++ b/arch/sparc/defconfig	Sat Apr  3 19:38:54 2004
@@ -10,6 +10,9 @@
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
 
 #
 # General setup
@@ -19,6 +22,16 @@
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=14
+# 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
@@ -50,9 +63,8 @@
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
 CONFIG_SUN_OPENPROMFS=m
-CONFIG_KCORE_ELF=y
-CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_MISC=m
 CONFIG_SUNOS_EMUL=y
 
@@ -62,6 +74,11 @@
 # CONFIG_PARPORT is not set
 
 #
+# Generic Driver Options
+#
+# CONFIG_DEBUG_DRIVER is not set
+
+#
 # Graphics support
 #
 # CONFIG_FB is not set
@@ -69,7 +86,6 @@
 #
 # Console display driver support
 #
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_MDA_CONSOLE is not set
 # CONFIG_PROM_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
@@ -89,7 +105,9 @@
 #
 CONFIG_SERIAL_SUNCORE=y
 CONFIG_SERIAL_SUNZILOG=y
+CONFIG_SERIAL_SUNZILOG_CONSOLE=y
 CONFIG_SERIAL_SUNSU=y
+CONFIG_SERIAL_SUNSU_CONSOLE=y
 # CONFIG_SERIAL_SUNSAB is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
@@ -111,13 +129,14 @@
 # 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=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
 # CONFIG_BLK_DEV_NBD is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
+# CONFIG_BLK_DEV_CARMEL is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=4096
 CONFIG_BLK_DEV_INITRD=y
@@ -130,12 +149,13 @@
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN_BOOL is not set
+# CONFIG_ISDN is not set
 
 #
-# SCSI support
+# SCSI device support
 #
 CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
 
 #
 # SCSI support type (disk, tape, CD-ROM)
@@ -156,6 +176,12 @@
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
@@ -164,10 +190,9 @@
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_SATA is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -175,21 +200,22 @@
 # 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_INITIO is not set
+# CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_NCR53C8XX 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 is not set
 CONFIG_SCSI_QLOGICPTI=m
+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_U14_34F is not set
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_SUNESP=y
@@ -200,6 +226,11 @@
 # CONFIG_FC4 is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -210,8 +241,6 @@
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_NETLINK_DEV=y
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
 CONFIG_UNIX=y
 CONFIG_NET_KEY=m
 CONFIG_INET=y
@@ -224,26 +253,36 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_INET_AH=y
 CONFIG_INET_ESP=y
-CONFIG_XFRM_USER=m
+CONFIG_INET_IPCOMP=y
 CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
 
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=y
 CONFIG_IP_SCTP=m
-# CONFIG_SCTP_ADLER32 is not set
 # CONFIG_SCTP_DBG_MSG is not set
 CONFIG_SCTP_DBG_OBJCNT=y
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
-# CONFIG_LLC is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE 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
@@ -261,22 +300,79 @@
 # Network testing
 #
 CONFIG_NET_PKTGEN=m
+CONFIG_NETDEVICES=y
 
 #
-# Network device support
+# ARCnet devices
 #
-CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
 CONFIG_DUMMY=m
 # CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
 CONFIG_TUN=m
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-CONFIG_SUNLANCE=m
-CONFIG_HAPPYMEAL=y
-# CONFIG_SUNBMAC is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_SUNLANCE=y
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNBMAC=m
 CONFIG_SUNQE=m
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
 # CONFIG_MYRI_SBUS is not set
-CONFIG_VORTEX=m
+# 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 is not set
+
+#
+# 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_RCPCI is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
 
 #
 # Amateur Radio support
@@ -284,6 +380,18 @@
 # CONFIG_HAMRADIO is not set
 
 #
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
 # Unix98 PTY support
 #
 CONFIG_UNIX98_PTYS=y
@@ -297,7 +405,7 @@
 #
 # Userland interfaces
 #
-CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV=y
 CONFIG_INPUT_MOUSEDEV_PSAUX=y
 CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
@@ -315,6 +423,7 @@
 # CONFIG_SERIO_I8042 is not set
 CONFIG_SERIO_SERPORT=m
 # CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
 
 #
 # Input Device Drivers
@@ -322,11 +431,13 @@
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=m
 CONFIG_KEYBOARD_SUNKBD=m
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=m
 CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
@@ -334,68 +445,93 @@
 #
 # File systems
 #
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_RT=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=m
 # CONFIG_QUOTA is not set
 CONFIG_QUOTACTL=y
 CONFIG_AUTOFS_FS=m
 CONFIG_AUTOFS4_FS=m
-# CONFIG_REISERFS_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# 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_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+# CONFIG_DEVPTS_FS_SECURITY is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+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=m
 # CONFIG_BEFS_DEBUG is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_FAT_FS is not set
 # CONFIG_EFS_FS is not set
 # CONFIG_CRAMFS is not set
-# CONFIG_TMPFS is not set
-CONFIG_RAMFS=y
-CONFIG_ISO9660_FS=m
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
-# CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
-CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-CONFIG_ROMFS_FS=m
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_UDF_FS is not set
 # CONFIG_UFS_FS is not set
-CONFIG_XFS_FS=m
-CONFIG_XFS_RT=y
-CONFIG_XFS_QUOTA=y
-CONFIG_XFS_POSIX_ACL=y
 
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
 # CONFIG_NFS_V4 is not set
-CONFIG_ROOT_NFS=y
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
-CONFIG_SUNRPC=y
+CONFIG_ROOT_NFS=y
 CONFIG_LOCKD=y
 # CONFIG_EXPORTFS is not set
-CONFIG_CIFS=m
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
 # CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
 # CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_AFS_FS=m
 CONFIG_RXRPC=m
-CONFIG_FS_MBCACHE=y
-CONFIG_FS_POSIX_ACL=y
 
 #
 # Partition Types
@@ -403,11 +539,11 @@
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
 CONFIG_SUN_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
@@ -448,7 +584,7 @@
 # CONFIG_NLS_UTF8 is not set
 
 #
-# Sound card support
+# Sound
 #
 # CONFIG_SOUND is not set
 
@@ -456,26 +592,28 @@
 # USB support
 #
 # CONFIG_USB is not set
-# CONFIG_USB_GADGET is not set
 
 #
-# Bluetooth support
+# USB Gadget Support
 #
-# CONFIG_BT is not set
+# CONFIG_USB_GADGET is not set
 
 #
-# Watchdog
+# Watchdog Cards
 #
-# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_WATCHDOG is not set
 
 #
 # Kernel hacking
 #
-CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_HIGHMEM is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
 
 #
 # Security options
@@ -492,13 +630,22 @@
 CONFIG_CRYPTO_MD5=y
 CONFIG_CRYPTO_SHA1=y
 CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
 CONFIG_CRYPTO_DES=y
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
 # CONFIG_CRYPTO_TEST is not set
 
 #
 # Library routines
 #
 CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff -Nru a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
--- a/arch/sparc/kernel/cpu.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sparc/kernel/cpu.c	Sat Apr  3 19:38:55 2004
@@ -4,6 +4,7 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/smp.h>
@@ -13,6 +14,9 @@
 #include <asm/head.h>
 #include <asm/psr.h>
 #include <asm/mbus.h>
+#include <asm/cpudata.h>
+
+DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
 
 struct cpu_iu_info {
   int psr_impl;
@@ -118,17 +122,15 @@
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
 
-char *sparc_cpu_type[NR_CPUS] = { 0 };
-char *sparc_fpu_type[NR_CPUS] = { 0 };
+char *sparc_cpu_type;
+char *sparc_fpu_type;
 
 unsigned int fsr_storage;
 
 void __init cpu_probe(void)
 {
 	int psr_impl, psr_vers, fpu_vers;
-	int i, cpuid, psr;
-
-	cpuid = hard_smp_processor_id();
+	int i, psr;
 
 	psr_impl = ((get_psr()>>28)&0xf);
 	psr_vers = ((get_psr()>>24)&0xf);
@@ -141,7 +143,7 @@
 	for(i = 0; i<NSPARCCHIPS; i++) {
 		if(linux_sparc_chips[i].psr_impl == psr_impl)
 			if(linux_sparc_chips[i].psr_vers == psr_vers) {
-				sparc_cpu_type[cpuid] = linux_sparc_chips[i].cpu_name;
+				sparc_cpu_type = linux_sparc_chips[i].cpu_name;
 				break;
 			}
 	}
@@ -153,7 +155,7 @@
 	for(i = 0; i<NSPARCFPU; i++) {
 		if(linux_sparc_fpu[i].psr_impl == psr_impl)
 			if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
-				sparc_fpu_type[cpuid] = linux_sparc_fpu[i].fp_name;
+				sparc_fpu_type = linux_sparc_fpu[i].fp_name;
 				break;
 			}
 	}
@@ -161,6 +163,6 @@
 	if(i == NSPARCFPU) {
 		printk("DEBUG: psr.impl = 0x%x  fsr.vers = 0x%x\n", psr_impl,
 			    fpu_vers);
-		sparc_fpu_type[cpuid] = linux_sparc_fpu[31].fp_name;
+		sparc_fpu_type = linux_sparc_fpu[31].fp_name;
 	}
 }
diff -Nru a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
--- a/arch/sparc/kernel/devices.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sparc/kernel/devices.c	Sat Apr  3 19:38:55 2004
@@ -1,6 +1,9 @@
 /* devices.c: Initial scan of the prom device tree for important
  *	      Sparc device nodes which we need to find.
  *
+ * This is based on the sparc64 version, but sun4m doesn't always use
+ * the hardware MIDs, so be careful.
+ *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
@@ -9,73 +12,135 @@
 #include <linux/threads.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/errno.h>
 
 #include <asm/page.h>
 #include <asm/oplib.h>
 #include <asm/smp.h>
 #include <asm/system.h>
-
-struct prom_cpuinfo linux_cpus[32];
-int linux_num_cpus = 0;
+#include <asm/cpudata.h>
 
 extern void cpu_probe(void);
 extern void clock_stop_probe(void); /* tadpole.c */
 extern void sun4c_probe_memerr_reg(void);
 
-void __init
-device_scan(void)
+static char *cpu_mid_prop(void)
+{
+	if (sparc_cpu_model == sun4d)
+		return "cpu-id";
+	return "mid";
+}
+
+static int check_cpu_node(int nd, int *cur_inst,
+			  int (*compare)(int, int, void *), void *compare_arg,
+			  int *prom_node, int *mid)
 {
 	char node_str[128];
-	int thismid;
 
-	prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
+	prom_getstring(nd, "device_type", node_str, sizeof(node_str));
+	if (strcmp(node_str, "cpu"))
+		return -ENODEV;
+	
+	if (!compare(nd, *cur_inst, compare_arg)) {
+		if (prom_node)
+			*prom_node = nd;
+		if (mid) {
+			*mid = prom_getintdefault(nd, cpu_mid_prop(), 0);
+			if (sparc_cpu_model == sun4m)
+				*mid &= 3;
+		}
+		return 0;
+	}
+
+	(*cur_inst)++;
+
+	return -ENODEV;
+}
+
+static int __cpu_find_by(int (*compare)(int, int, void *), void *compare_arg,
+			 int *prom_node, int *mid)
+{
+	int nd, cur_inst, err;
+
+	nd = prom_root_node;
+	cur_inst = 0;
+
+	err = check_cpu_node(nd, &cur_inst, compare, compare_arg,
+			     prom_node, mid);
+	if (!err)
+		return 0;
+
+	nd = prom_getchild(nd);
+	while ((nd = prom_getsibling(nd)) != 0) {
+		err = check_cpu_node(nd, &cur_inst, compare, compare_arg,
+				     prom_node, mid);
+		if (!err)
+			return 0;
+	}
+
+	return -ENODEV;
+}
+
+static int cpu_instance_compare(int nd, int instance, void *_arg)
+{
+	int desired_instance = (int) _arg;
+
+	if (instance == desired_instance)
+		return 0;
+	return -ENODEV;
+}
+
+int cpu_find_by_instance(int instance, int *prom_node, int *mid)
+{
+	return __cpu_find_by(cpu_instance_compare, (void *)instance,
+			     prom_node, mid);
+}
+
+static int cpu_mid_compare(int nd, int instance, void *_arg)
+{
+	int desired_mid = (int) _arg;
+	int this_mid;
+
+	this_mid = prom_getintdefault(nd, cpu_mid_prop(), 0);
+	if (this_mid == desired_mid
+	    || (sparc_cpu_model == sun4m && (this_mid & 3) == desired_mid))
+		return 0;
+	return -ENODEV;
+}
+
+int cpu_find_by_mid(int mid, int *prom_node)
+{
+	return __cpu_find_by(cpu_mid_compare, (void *)mid,
+			     prom_node, NULL);
+}
+
+/* sun4m uses truncated mids since we base the cpuid on the ttable/irqset
+ * address (0-3).  This gives us the true hardware mid, which might have
+ * some other bits set.  On 4d hardware and software mids are the same.
+ */
+int cpu_get_hwmid(int prom_node)
+{
+	return prom_getintdefault(prom_node, cpu_mid_prop(), -ENODEV);
+}
 
+void __init device_scan(void)
+{
 	prom_printf("Booting Linux...\n");
-	if(strcmp(node_str, "cpu") == 0) {
-		linux_num_cpus++;
-	} else {
-		int scan;
-		scan = prom_getchild(prom_root_node);
-		/* One can look it up in PROM instead */
-		while ((scan = prom_getsibling(scan)) != 0) {
-			prom_getstring(scan, "device_type",
-				       node_str, sizeof(node_str));
-			if (strcmp(node_str, "cpu") == 0) {
-				linux_cpus[linux_num_cpus].prom_node = scan;
-				prom_getproperty(scan, "mid",
-						 (char *) &thismid, sizeof(thismid));
-				linux_cpus[linux_num_cpus].mid = thismid;
-				printk("Found CPU %d <node=%08lx,mid=%d>\n",
-				       linux_num_cpus, (unsigned long) scan, thismid);
-				linux_num_cpus++;
-			}
-		}
-		if (linux_num_cpus == 0 && sparc_cpu_model == sun4d) {
-			scan = prom_getchild(prom_root_node);
-			for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
-			     scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
-				int node = prom_getchild(scan);
-
-				prom_getstring(node, "device_type",
-					       node_str, sizeof(node_str));
-				if (strcmp(node_str, "cpu") == 0) {
-					prom_getproperty(node, "cpu-id",
-							 (char *) &thismid, sizeof(thismid));
-					linux_cpus[linux_num_cpus].prom_node = node;
-					linux_cpus[linux_num_cpus].mid = thismid;
-					printk("Found CPU %d <node=%08lx,mid=%d>\n", 
-					       linux_num_cpus, (unsigned long) node, thismid);
-					linux_num_cpus++;
-				}
-			}
-		}
-		if (linux_num_cpus == 0) {
-			printk("No CPU nodes found, cannot continue.\n");
+
+#ifndef CONFIG_SMP
+	{
+		int err, cpu_node;
+		err = cpu_find_by_instance(0, &cpu_node, NULL);
+		if (err) {
 			/* Probably a sun4e, Sun is trying to trick us ;-) */
+			prom_printf("No cpu nodes, cannot continue\n");
 			prom_halt();
 		}
-		printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
+		cpu_data(0).clock_tick = prom_getintdefault(cpu_node,
+							    "clock-frequency",
+							    0);
 	}
+#endif /* !CONFIG_SMP */
 
 	cpu_probe();
 #ifdef CONFIG_SUN_AUXIO
diff -Nru a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
--- a/arch/sparc/kernel/entry.S	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc/kernel/entry.S	Sat Apr  3 19:38:43 2004
@@ -32,12 +32,13 @@
 #include <asm/obio.h>
 #include <asm/mxcc.h>
 #include <asm/thread_info.h>
+#include <asm/param.h>
 
 #include <asm/asmmacro.h>
 
 #define curptr      g6
 
-#define NR_SYSCALLS 272      /* Each OS is different... */
+#define NR_SYSCALLS 273      /* Each OS is different... */
 
 /* These are just handy. */
 #define _SV	save	%sp, -STACKFRAME_SZ, %sp
@@ -287,10 +288,9 @@
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
-	mov	%l7, %o0		! trap number
-	mov	%l0, %o1		! psr
+	add	%sp, STACKFRAME_SZ, %o0	! pt_regs
 	call	do_hw_interrupt
-	 mov	%l1, %o2		! pc
+	 mov	%l7, %o1		! trap number
 
 	RESTORE_ALL
 	
@@ -349,21 +349,15 @@
 	 * for cross calls.  That has a separate entry point below.
 	 */
 maybe_smp4m_msg:
-	GET_PROCESSOR_MID(o3, o2)
+	GET_PROCESSOR4M_ID(o3)
 	set	sun4m_interrupts, %l5
 	ld	[%l5], %o5
-	sethi	%hi(0x60000000), %o4
+	sethi	%hi(0x40000000), %o2
 	sll	%o3, 12, %o3
 	ld	[%o5 + %o3], %o1
-	andcc	%o1, %o4, %g0
+	andcc	%o1, %o2, %g0
 	be,a	smp4m_ticker
 	 cmp	%l7, 14
-	sethi	%hi(0x40000000), %o2
-	add	%o5, %o3, %o5
-	andcc	%o1, %o2, %g0
-	be,a	1f
-	 sethi	%hi(0x20000000), %o2
-1:
 	st	%o2, [%o5 + 0x4]
 	WRITE_PAUSE
 	ld	[%o5], %g0
@@ -373,15 +367,9 @@
 	WRITE_PAUSE
 	wr	%l4, PSR_ET, %psr
 	WRITE_PAUSE
-	srl	%o2, (16+14), %o2
-	tst	%o2
-	bne	2f
-	 nop
 	call	smp_reschedule_irq
-	 add	%o7, 8, %o7
-2:
-	call	smp_stop_cpu_irq
 	 nop
+
 	RESTORE_ALL
 
 	.align	4
@@ -389,7 +377,7 @@
 linux_trap_ipi15_sun4m:
 	SAVE_ALL
 	sethi	%hi(0x80000000), %o2
-	GET_PROCESSOR_MID(o0, o1)
+	GET_PROCESSOR4M_ID(o0)
 	set	sun4m_interrupts, %l5
 	ld	[%l5], %o5
 	sll	%o0, 12, %o0
@@ -1808,36 +1796,37 @@
 	retl
 	 nop
 
-	.globl	ndelay
-ndelay:
+	/* __ndelay and __udelay take two arguments:
+	 * 0 - nsecs or usecs to delay
+	 * 1 - per_cpu udelay_val (loops per jiffy)
+	 *
+	 * Note that ndelay gives HZ times higher resolution but has a 10ms
+	 * limit.  udelay can handle up to 1s.
+	 */
+	.globl	__ndelay
+__ndelay:
 	save	%sp, -STACKFRAME_SZ, %sp
 	mov	%i0, %o0
 	call	.umul
-	 mov	5, %o1
+	 mov	0x1ad, %o1		! 2**32 / (1 000 000 000 / HZ)
+	call	.umul
+	 mov	%i1, %o1		! udelay_val
 	ba	delay_continue
-	 nop
+	 mov	%o1, %o0		! >>32 later for better resolution
 
-	.globl	udelay
-udelay:
+	.globl	__udelay
+__udelay:
 	save	%sp, -STACKFRAME_SZ, %sp
 	mov	%i0, %o0
 	sethi	%hi(0x10c6), %o1
 	call	.umul
-	 or	%o1, %lo(0x10c6), %o1
-delay_continue:
-#ifndef CONFIG_SMP
-	sethi	%hi(loops_per_jiffy), %o3
+	 or	%o1, %lo(0x10c6), %o1	! 2**32 / 1 000 000
 	call	.umul
-	 ld	[%o3 + %lo(loops_per_jiffy)], %o1
-#else
-	GET_PROCESSOR_OFFSET(o4, o2)
-	set	cpu_data, %o3
-	call	.umul
-	 ld	[%o3 + %o4], %o1
-#endif
+	 mov	%i1, %o1		! udelay_val
 	call	.umul
-	 mov	100, %o0
+	 mov	HZ, %o0			! >>32 earlier for wider range
 
+delay_continue:
 	cmp	%o0, 0x0
 1:
 	bne	1b
diff -Nru a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
--- a/arch/sparc/kernel/head.S	Sat Apr  3 19:38:42 2004
+++ b/arch/sparc/kernel/head.S	Sat Apr  3 19:38:42 2004
@@ -746,9 +746,6 @@
 		jmpl	%g1, %g0
 		 nop
 
-	/* This is to align init_thread_union properly, be careful. -DaveM */
-	.align	8192
-
 /* The code above should be at beginning and we have to take care about
  * short jumps, as branching to .text.init section from .text is usually
  * impossible */
diff -Nru a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
--- a/arch/sparc/kernel/init_task.c	Sat Apr  3 19:38:44 2004
+++ b/arch/sparc/kernel/init_task.c	Sat Apr  3 19:38:44 2004
@@ -21,5 +21,7 @@
  * If this is not aligned on a 8k boundry, then you should change code
  * in etrap.S which assumes it.
  */
-__asm__(".section \".text\",#alloc\n");
-union thread_union init_thread_union = { INIT_THREAD_INFO(init_task) };
+union thread_union init_thread_union
+	__attribute__((section (".text")))
+	__attribute__((aligned (THREAD_SIZE)))
+	= { INIT_THREAD_INFO(init_task) };
diff -Nru a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
--- a/arch/sparc/kernel/ioport.c	Sat Apr  3 19:38:56 2004
+++ b/arch/sparc/kernel/ioport.c	Sat Apr  3 19:38:56 2004
@@ -360,7 +360,7 @@
 
 /*
  */
-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 @@
 #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 @@
  * 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 @@
  * 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 @@
 /* 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 -Nru a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
--- a/arch/sparc/kernel/module.c	Sat Apr  3 19:38:40 2004
+++ b/arch/sparc/kernel/module.c	Sat Apr  3 19:38:40 2004
@@ -36,7 +36,9 @@
            table entries. */
 }
 
-/* Make generic code ignore STT_REGISTER dummy undefined symbols.  */
+/* Make generic code ignore STT_REGISTER dummy undefined symbols,
+ * and replace references to .func with func as in ppc64's dedotify.
+ */
 int module_frob_arch_sections(Elf_Ehdr *hdr,
 			      Elf_Shdr *sechdrs,
 			      char *secstrings,
@@ -44,7 +46,7 @@
 {
 	unsigned int symidx;
 	Elf32_Sym *sym;
-	const char *strtab;
+	char *strtab;
 	int i;
 
 	for (symidx = 0; sechdrs[symidx].sh_type != SHT_SYMTAB; symidx++) {
@@ -57,9 +59,15 @@
 	strtab = (char *)sechdrs[sechdrs[symidx].sh_link].sh_addr;
 
 	for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) {
-		if (sym[i].st_shndx == SHN_UNDEF &&
-		    ELF32_ST_TYPE(sym[i].st_info) == STT_REGISTER)
-			sym[i].st_shndx = SHN_ABS;
+		if (sym[i].st_shndx == SHN_UNDEF) {
+			if (ELF32_ST_TYPE(sym[i].st_info) == STT_REGISTER)
+				sym[i].st_shndx = SHN_ABS;
+			else {
+				char *name = strtab + sym[i].st_name;
+				if (name[0] == '.')
+					memmove(name, name+1, strlen(name));
+			}
+		}
 	}
 	return 0;
 }
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c	Sat Apr  3 19:38:41 2004
+++ b/arch/sparc/kernel/process.c	Sat Apr  3 19:38:41 2004
@@ -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>
@@ -42,6 +40,7 @@
 #include <asm/processor.h>
 #include <asm/psr.h>
 #include <asm/elf.h>
+#include <asm/unistd.h>
 
 /* 
  * Power management idle function 
diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
--- a/arch/sparc/kernel/setup.c	Sat Apr  3 19:38:40 2004
+++ b/arch/sparc/kernel/setup.c	Sat Apr  3 19:38:40 2004
@@ -46,6 +46,7 @@
 #include <asm/idprom.h>
 #include <asm/hardirq.h>
 #include <asm/machines.h>
+#include <asm/cpudata.h>
 
 struct screen_info screen_info = {
 	0, 0,			/* orig-x, orig-y */
@@ -330,6 +331,7 @@
 		if (highest_paddr < top)
 			highest_paddr = top;
 	}
+	pfn_base = phys_base >> PAGE_SHIFT;
 
 	if (!root_flags)
 		root_mountflags &= ~MS_RDONLY;
@@ -389,18 +391,11 @@
 }
 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[];
+extern char *sparc_cpu_type;
+extern char *sparc_fpu_type;
 
 static int show_cpuinfo(struct seq_file *m, void *__unused)
 {
-	int cpuid = hard_smp_processor_id();
-
 	seq_printf(m,
 		   "cpu\t\t: %s\n"
 		   "fpu\t\t: %s\n"
@@ -410,26 +405,28 @@
 		   "ncpus probed\t: %d\n"
 		   "ncpus active\t: %d\n"
 #ifndef CONFIG_SMP
-		   "BogoMips\t: %lu.%02lu\n"
+		   "CPU0Bogo\t: %lu.%02lu\n"
+		   "CPU0ClkTck\t: %ld\n"
 #endif
 		   ,
-		   sparc_cpu_type[cpuid] ? : "undetermined",
-		   sparc_fpu_type[cpuid] ? : "undetermined",
+		   sparc_cpu_type ? sparc_cpu_type : "undetermined",
+		   sparc_fpu_type ? sparc_fpu_type : "undetermined",
 		   romvec->pv_romvers,
 		   prom_rev,
 		   romvec->pv_printrev >> 16,
-		   (short) romvec->pv_printrev,
+		   romvec->pv_printrev & 0xffff,
 		   &cputypval,
-		   linux_num_cpus,
+		   num_possible_cpus(),
 		   num_online_cpus()
 #ifndef CONFIG_SMP
-		   , loops_per_jiffy/(500000/HZ),
-		   (loops_per_jiffy/(5000/HZ)) % 100
+		   , cpu_data(0).udelay_val/(500000/HZ),
+		   (cpu_data(0).udelay_val/(5000/HZ)) % 100,
+		   cpu_data(0).clock_tick
 #endif
 		);
 
 #ifdef CONFIG_SMP
-	smp_bogo_info(m);
+	smp_bogo(m);
 #endif
 	mmu_info(m);
 #ifdef CONFIG_SMP
diff -Nru a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
--- a/arch/sparc/kernel/signal.c	Sat Apr  3 19:38:54 2004
+++ b/arch/sparc/kernel/signal.c	Sat Apr  3 19:38:54 2004
@@ -1128,9 +1128,9 @@
 
 	/* Now see if we want to update the new state. */
 	if (ssptr) {
-		void *ss_sp;
+		char *ss_sp;
 
-		if (get_user((long)ss_sp, &ssptr->the_stack))
+		if (get_user(ss_sp, &ssptr->the_stack))
 			goto out;
 		/* If the current stack was set with sigaltstack, don't
 		   swap stacks while we are on it.  */
diff -Nru a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
--- a/arch/sparc/kernel/smp.c	Sat Apr  3 19:38:42 2004
+++ b/arch/sparc/kernel/smp.c	Sat Apr  3 19:38:42 2004
@@ -2,6 +2,7 @@
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 2004 Keith M Wesolowski (wesolows@foobazco.org)
  */
 
 #include <asm/head.h>
@@ -19,11 +20,11 @@
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/cache.h>
+#include <linux/delay.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 
-#include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
@@ -32,26 +33,12 @@
 #include <asm/hardirq.h>
 #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
+#include <asm/cpudata.h>
 
 volatile int smp_processors_ready = 0;
-unsigned long cpu_present_map = 0;
 int smp_num_cpus = 1;
 int smp_threads_ready=0;
-unsigned char mid_xlate[NR_CPUS] = { 0, 0, 0, 0, };
 volatile unsigned long cpu_callin_map[NR_CPUS] __initdata = {0,};
-#ifdef NOTUSED
-volatile unsigned long smp_spinning[NR_CPUS] = { 0, };
-#endif
-unsigned long smp_proc_in_lock[NR_CPUS] = { 0, };
-struct cpuinfo_sparc cpu_data[NR_CPUS];
-unsigned long cpu_offset[NR_CPUS];
 unsigned char boot_cpu_id = 0;
 unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
 int smp_activated = 0;
@@ -59,6 +46,9 @@
 volatile int __cpu_logical_map[NR_CPUS];
 cycles_t cacheflush_time = 0; /* XXX */
 
+cpumask_t cpu_online_map = CPU_MASK_NONE;
+cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+
 /* The only guaranteed locking primitive available on all Sparc
  * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically
  * places the current byte at the effective address into dest_reg and
@@ -75,40 +65,23 @@
 volatile int smp_process_available=0;
 volatile int smp_commenced = 0;
 
-/* Not supported on Sparc yet. */
-void __init smp_setup(char *str, int *ints)
-{
-}
-
-/*
- *	The bootstrap kernel entry code has set these up. Save them for
- *	a given CPU
- */
-
 void __init smp_store_cpu_info(int id)
 {
-	cpu_data[id].udelay_val = loops_per_jiffy; /* this is it on sparc. */
-}
+	int cpu_node;
 
-void __init smp_commence(void)
-{
-	/*
-	 *	Lets the callin's below out of their loop.
-	 */
-	local_flush_cache_all();
-	local_flush_tlb_all();
-	smp_commenced = 1;
-	local_flush_cache_all();
-	local_flush_tlb_all();
-}
+	cpu_data(id).udelay_val = loops_per_jiffy;
 
-extern int cpu_idle(void);
+	cpu_find_by_mid(id, &cpu_node);
+	cpu_data(id).clock_tick = prom_getintdefault(cpu_node,
+						     "clock-frequency", 0);
+	cpu_data(id).prom_node = cpu_node;
+	cpu_data(id).mid = cpu_get_hwmid(cpu_node);
+	if (cpu_data(id).mid < 0)
+		panic("No MID found for CPU%d at node 0x%08d", id, cpu_node);
+}
 
-/* Activate a secondary processor. */
-int start_secondary(void *unused)
+void __init smp_cpus_done(unsigned int max_cpus)
 {
-	prom_printf("Start secondary called. Should not happen\n");
-	return cpu_idle();
 }
 
 void cpu_panic(void)
@@ -117,11 +90,6 @@
 	panic("SMP bolixed\n");
 }
 
-/*
- *	Cycle through the processors asking the PROM to start each one.
- */
- 
-extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 struct linux_prom_registers smp_penguin_ctable __initdata = { 0 };
 
 void __init smp_boot_cpus(void)
@@ -137,12 +105,11 @@
 
 void smp_send_reschedule(int cpu)
 {
-	smp_message_pass (cpu, MSG_RESCHEDULE, 0, 0);
+	/* See sparc64 */
 }
 
 void smp_send_stop(void)
 {
-	smp_message_pass (MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
 }
 
 void smp_flush_cache_all(void)
@@ -245,22 +212,6 @@
 	local_flush_sig_insns(mm, insn_addr);
 }
 
-/* Reschedule call back. */
-void smp_reschedule_irq(void)
-{
-	current->work.need_resched = 1;
-}
-
-/* Stopping processors. */
-void smp_stop_cpu_irq(void)
-{
-	local_irq_enable();
-	while(1)
-		barrier();
-}
-
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
 extern unsigned int lvl14_resolution;
 
 /* /proc/profile writes can call this, don't __init it please. */
@@ -277,36 +228,52 @@
 
 	spin_lock_irqsave(&prof_setup_lock, flags);
 	for(i = 0; i < NR_CPUS; i++) {
-		if(cpu_present_map & (1 << i)) {
-			load_profile_irq(mid_xlate[i], lvl14_resolution / multiplier);
-			prof_multiplier[i] = multiplier;
-		}
+		if (cpu_possible(i))
+			load_profile_irq(i, lvl14_resolution / multiplier);
+		prof_multiplier(i) = multiplier;
 	}
 	spin_unlock_irqrestore(&prof_setup_lock, flags);
 
 	return 0;
 }
 
-void smp_bogo_info(struct seq_file *m)
+void __init smp_prepare_cpus(unsigned int maxcpus)
+{
+}
+
+void __devinit smp_prepare_boot_cpu(void)
+{
+	current_thread_info()->cpu = hard_smp_processor_id();
+	cpu_set(smp_processor_id(), cpu_online_map);
+	cpu_set(smp_processor_id(), phys_cpu_present_map);
+}
+
+int __devinit __cpu_up(unsigned int cpu)
+{
+	panic("smp doesn't work\n");
+}
+
+void smp_bogo(struct seq_file *m)
 {
 	int i;
 	
 	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_present_map & (1 << i))
+		if (cpu_online(i))
 			seq_printf(m,
 				   "Cpu%dBogo\t: %lu.%02lu\n", 
 				   i,
-				   cpu_data[i].udelay_val/(500000/HZ),
-				   (cpu_data[i].udelay_val/(5000/HZ))%100);
+				   cpu_data(i).udelay_val/(500000/HZ),
+				   (cpu_data(i).udelay_val/(5000/HZ))%100);
 	}
 }
 
 void smp_info(struct seq_file *m)
 {
 	int i;
-	
+
+	seq_printf(m, "State:\n");
 	for (i = 0; i < NR_CPUS; i++) {
-		if (cpu_present_map & (1 << i))
+		if (cpu_online(i))
 			seq_printf(m, "CPU%d\t\t: online\n", i);
 	}
 }
diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
--- a/arch/sparc/kernel/sparc_ksyms.c	Sat Apr  3 19:38:41 2004
+++ b/arch/sparc/kernel/sparc_ksyms.c	Sat Apr  3 19:38:41 2004
@@ -92,31 +92,21 @@
 extern void ___clear_bit(void);
 extern void ___change_bit(void);
 
-/* One thing to note is that the way the symbols of the mul/div
- * support routines are named is a mess, they all start with
- * a '.' which makes it a bitch to export, here is the trick:
+/* Alias functions whose names begin with "." and export the aliases.
+ * The module references will be fixed up by module_frob_arch_sections.
  */
+#define DOT_ALIAS2(__ret, __x, __arg1, __arg2) \
+	extern __ret __x(__arg1, __arg2) \
+	             __attribute__((weak, alias("." # __x)));
+
+DOT_ALIAS2(int, div, int, int)
+DOT_ALIAS2(int, mul, int, int)
+DOT_ALIAS2(int, rem, int, int)
+DOT_ALIAS2(unsigned, udiv, unsigned, unsigned)
+DOT_ALIAS2(unsigned, umul, unsigned, unsigned)
+DOT_ALIAS2(unsigned, urem, unsigned, unsigned)
 
-/* If the interface of any of these special functions does ever
- * change in an incompatible way, you must modify this.
- */
-#define DOT_PROTO(sym) extern int __dot_##sym(int, int)
-
-#ifdef __GENKSYMS__
-#define EXPORT_SYMBOL_DOT(sym)						\
-	DOT_PROTO(sym);							\
-	EXPORT_SYMBOL(__dot_ ## sym)
-#else /* !__GENKSYMS__ */
-#define EXPORT_SYMBOL_DOT(sym)						\
-	DOT_PROTO(sym) __asm__("." # sym);				\
-	__CRC_SYMBOL(__dot_##sym, "")					\
-	static const char __kstrtab___dot_##sym[]			\
-	__attribute__((section("__ksymtab_strings")))			\
-	= "." #sym;							\
-	static const struct kernel_symbol __ksymtab___dot_##sym		\
-	__attribute__((section("__ksymtab")))				\
-	= { (unsigned long)&__dot_##sym, __kstrtab___dot_##sym }
-#endif
+#undef DOT_ALIAS2
 
 /* used by various drivers */
 EXPORT_SYMBOL(sparc_cpu_model);
@@ -145,6 +135,7 @@
 
 EXPORT_SYMBOL(sparc_valid_addr_bitmap);
 EXPORT_SYMBOL(phys_base);
+EXPORT_SYMBOL(pfn_base);
 
 /* Atomic operations. */
 EXPORT_SYMBOL(___atomic24_add);
@@ -164,8 +155,8 @@
 EXPORT_SYMBOL(__cpu_logical_map);
 #endif
 
-EXPORT_SYMBOL(udelay);
-EXPORT_SYMBOL(ndelay);
+EXPORT_SYMBOL(__udelay);
+EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(rtc_lock);
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
@@ -179,21 +170,20 @@
 /* EXPORT_SYMBOL(iounit_map_dma_init); */
 /* EXPORT_SYMBOL(iounit_map_dma_page); */
 
-/* Btfixup stuff cannot have versions, it would be complicated too much */
 #ifndef CONFIG_SMP
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(___xchg32));
+EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
 #else
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(__smp_processor_id));
+EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id));
 #endif
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(enable_irq));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(disable_irq));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(__irq_itoa));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_unlockarea));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_lockarea));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_get_scsi_sgl));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_get_scsi_one));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_sgl));
-EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_one));
+EXPORT_SYMBOL(BTFIXUP_CALL(enable_irq));
+EXPORT_SYMBOL(BTFIXUP_CALL(disable_irq));
+EXPORT_SYMBOL(BTFIXUP_CALL(__irq_itoa));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_one));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_sgl));
+EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one));
 
 #ifdef CONFIG_SBUS
 EXPORT_SYMBOL(sbus_root);
@@ -205,8 +195,10 @@
 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 +210,10 @@
 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);
@@ -265,15 +260,15 @@
 /* sparc library symbols */
 EXPORT_SYMBOL(bcopy);
 EXPORT_SYMBOL(memchr);
-EXPORT_SYMBOL_NOVERS(memscan);
-EXPORT_SYMBOL_NOVERS(strlen);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL_NOVERS(strncmp);
+EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strpbrk);
@@ -303,28 +298,24 @@
 /* Cache flushing.  */
 EXPORT_SYMBOL(sparc_flush_page_to_ram);
 
-/* No version information on this, heavily used in inline asm,
- * and will always be 'void __ret_efault(void)'.
- */
-EXPORT_SYMBOL_NOVERS(__ret_efault);
+EXPORT_SYMBOL(__ret_efault);
 
-/* No version information on these, as gcc produces such symbols. */
-EXPORT_SYMBOL_NOVERS(memcmp);
-EXPORT_SYMBOL_NOVERS(memcpy);
-EXPORT_SYMBOL_NOVERS(memset);
-EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL_NOVERS(__ashrdi3);
-EXPORT_SYMBOL_NOVERS(__ashldi3);
-EXPORT_SYMBOL_NOVERS(__lshrdi3);
-EXPORT_SYMBOL_NOVERS(__muldi3);
-EXPORT_SYMBOL_NOVERS(__divdi3);
-
-EXPORT_SYMBOL_DOT(rem);
-EXPORT_SYMBOL_DOT(urem);
-EXPORT_SYMBOL_DOT(mul);
-EXPORT_SYMBOL_DOT(umul);
-EXPORT_SYMBOL_DOT(div);
-EXPORT_SYMBOL_DOT(udiv);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__divdi3);
+
+EXPORT_SYMBOL(rem);
+EXPORT_SYMBOL(urem);
+EXPORT_SYMBOL(mul);
+EXPORT_SYMBOL(umul);
+EXPORT_SYMBOL(div);
+EXPORT_SYMBOL(udiv);
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 EXPORT_SYMBOL(do_BUG);
diff -Nru a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
--- a/arch/sparc/kernel/sun4d_irq.c	Sat Apr  3 19:38:40 2004
+++ b/arch/sparc/kernel/sun4d_irq.c	Sat Apr  3 19:38:40 2004
@@ -472,9 +472,9 @@
 static void __init sun4d_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
 {
 	int irq;
-	extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 	int cpu;
 	struct resource r;
+	int mid;
 
 	/* Map the User Timer registers. */
 	memset(&r, 0, sizeof(r));
@@ -502,9 +502,12 @@
 	
 	/* Enable user timer free run for CPU 0 in BW */
 	/* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
-    
-	for(cpu = 0; cpu < linux_num_cpus; cpu++)
-		sun4d_load_profile_irq((linux_cpus[cpu].mid >> 3), 0);
+
+	cpu = 0;
+	while (!cpu_find_by_instance(cpu, NULL, &mid)) {
+		sun4d_load_profile_irq(mid >> 3, 0);
+		cpu++;
+	}
 		
 #ifdef CONFIG_SMP
 	{
diff -Nru a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
--- a/arch/sparc/kernel/sun4d_smp.c	Sat Apr  3 19:38:41 2004
+++ b/arch/sparc/kernel/sun4d_smp.c	Sat Apr  3 19:38:41 2004
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -31,14 +32,13 @@
 #include <asm/hardirq.h>
 #include <asm/sbus.h>
 #include <asm/sbi.h>
-
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/cpudata.h>
 
 #define IRQ_CROSS_CALL		15
 
 extern ctxd_t *srmmu_ctx_table_phys;
-extern int linux_num_cpus;
 
 extern void calibrate_delay(void);
 
@@ -47,11 +47,8 @@
 extern int smp_num_cpus;
 static int smp_highest_cpu;
 extern int smp_threads_ready;
-extern unsigned char mid_xlate[NR_CPUS];
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
-extern unsigned long smp_proc_in_lock[NR_CPUS];
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
-extern unsigned long cpu_offset[NR_CPUS];
 extern unsigned char boot_cpu_id;
 extern int smp_activated;
 extern volatile int __cpu_number_map[NR_CPUS];
@@ -161,7 +158,6 @@
  *	Cycle through the processors asking the PROM to start each one.
  */
  
-extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 extern struct linux_prom_registers smp_penguin_ctable;
 extern unsigned long trapbase_cpu1[];
 extern unsigned long trapbase_cpu2[];
@@ -170,34 +166,31 @@
 void __init smp4d_boot_cpus(void)
 {
 	int cpucount = 0;
-	int i = 0;
+	int i, mid;
 
 	printk("Entering SMP Mode...\n");
 	
-	for (i = 0; i < NR_CPUS; i++)
-		cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
-		
 	if (boot_cpu_id)
 		current_set[0] = NULL;
 
 	local_irq_enable();
 	cpu_present_map = 0;
-	for(i=0; i < linux_num_cpus; i++)
-		cpu_present_map |= (1<<linux_cpus[i].mid);
+
+	/* XXX This whole thing has to go.  See sparc64. */
+	for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
+		cpu_present_map |= (1<<mid);
 	SMP_PRINTK(("cpu_present_map %08lx\n", cpu_present_map));
 	for(i=0; i < NR_CPUS; i++)
 		__cpu_number_map[i] = -1;
 	for(i=0; i < NR_CPUS; i++)
 		__cpu_logical_map[i] = -1;
-	for(i=0; i < NR_CPUS; i++)
-		mid_xlate[i] = i;
 	__cpu_number_map[boot_cpu_id] = 0;
 	__cpu_logical_map[0] = boot_cpu_id;
-	current->cpu = boot_cpu_id;
+	current_thread_info()->cpu = boot_cpu_id;
 	smp_store_cpu_info(boot_cpu_id);
 	smp_setup_percpu_timer();
 	local_flush_cache_all();
-	if(linux_num_cpus == 1)
+	if (cpu_find_by_instance(1, NULL, NULL))
 		return;  /* Not an MP box. */
 	SMP_PRINTK(("Iterating over CPUs\n"));
 	for(i = 0; i < NR_CPUS; i++) {
@@ -218,15 +211,14 @@
 
 			p = prev_task(&init_task);
 
-			p->cpu = i;
+			init_idle(p, i);
 
-			current_set[i] = p;
+			current_set[i] = p->thread_info;
 
 			unhash_process(p);
 
-			for (no = 0; no < linux_num_cpus; no++)
-				if (linux_cpus[no].mid == i)
-					break;
+			for (no = 0; !cpu_find_by_instance(no, NULL, &mid)
+				     && mid != i; no++) ;
 
 			/*
 			 * Initialize the contexts table
@@ -238,9 +230,9 @@
 			smp_penguin_ctable.reg_size = 0;
 
 			/* whirrr, whirrr, whirrrrrrrrr... */
-			SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, linux_cpus[no].prom_node));
+			SMP_PRINTK(("Starting CPU %d at %p task %d node %08x\n", i, entry, cpucount, cpu_data(no).prom_node));
 			local_flush_cache_all();
-			prom_startcpu(linux_cpus[no].prom_node,
+			prom_startcpu(cpu_data(no).prom_node,
 				      &smp_penguin_ctable, 0, (char *)entry);
 				      
 			SMP_PRINTK(("prom_startcpu returned :)\n"));
@@ -275,7 +267,7 @@
 		
 		for(i = 0; i < NR_CPUS; i++) {
 			if(cpu_present_map & (1 << i)) {
-				bogosum += cpu_data[i].udelay_val;
+				bogosum += cpu_data(i).udelay_val;
 				smp_highest_cpu = i;
 			}
 		}
@@ -337,12 +329,12 @@
 
 		{
 			/* If you make changes here, make sure gcc generates proper code... */
-			smpfunc_t f asm("i0") = func;
-			unsigned long a1 asm("i1") = arg1;
-			unsigned long a2 asm("i2") = arg2;
-			unsigned long a3 asm("i3") = arg3;
-			unsigned long a4 asm("i4") = arg4;
-			unsigned long a5 asm("i5") = arg5;
+			register smpfunc_t f asm("i0") = func;
+			register unsigned long a1 asm("i1") = arg1;
+			register unsigned long a2 asm("i2") = arg2;
+			register unsigned long a3 asm("i3") = arg3;
+			register unsigned long a4 asm("i4") = arg4;
+			register unsigned long a5 asm("i5") = arg5;
 
 			__asm__ __volatile__(
 				"std %0, [%6]\n\t"
@@ -429,9 +421,6 @@
 	panic("Bogon SMP message pass.");
 }
 
-extern unsigned int prof_multiplier[NR_CPUS];
-extern unsigned int prof_counter[NR_CPUS];
-
 extern void sparc_do_profile(unsigned long pc, unsigned long o7);
 
 void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
@@ -454,14 +443,14 @@
 	if(!user_mode(regs))
 		sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
 
-	if(!--prof_counter[cpu]) {
+	if(!--prof_counter(cpu)) {
 		int user = user_mode(regs);
 
 		irq_enter();
 		update_process_times(user);
 		irq_exit();
 
-		prof_counter[cpu] = prof_multiplier[cpu];
+		prof_counter(cpu) = prof_multiplier(cpu);
 	}
 }
 
@@ -471,7 +460,7 @@
 {
 	int cpu = hard_smp4d_processor_id();
 
-	prof_counter[cpu] = prof_multiplier[cpu] = 1;
+	prof_counter(cpu) = prof_multiplier(cpu) = 1;
 	load_profile_irq(cpu, lvl14_resolution);
 }
 
diff -Nru a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
--- a/arch/sparc/kernel/sun4m_irq.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc/kernel/sun4m_irq.c	Sat Apr  3 19:38:43 2004
@@ -292,8 +292,8 @@
 		prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
 		prom_halt();
 	}
-    
-	if(linux_num_cpus > 1) {
+   
+	if (!cpu_find_by_instance(1, NULL, NULL)) {
 		for(cpu = 0; cpu < 4; cpu++)
 			sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
 		sun4m_interrupts->set = SUN4M_INT_E14;
@@ -327,6 +327,7 @@
 	struct linux_prom_registers int_regs[PROMREG_MAX];
 	int num_regs;
 	struct resource r;
+	int mid;
     
 	local_irq_disable();
 	if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
@@ -364,10 +365,10 @@
 	sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
 
 	sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
-	for (i=0; i<linux_num_cpus; i++)
-		sun4m_interrupts->cpu_intregs[i].clear = ~0x17fff;
-    
-	if (linux_num_cpus > 1) {
+	for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
+		sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
+
+	if (!cpu_find_by_instance(1, NULL, NULL)) {
 		/* system wide interrupts go to cpu 0, this should always
 		 * be safe because it is guaranteed to be fitted or OBP doesn't
 		 * come up
diff -Nru a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
--- a/arch/sparc/kernel/sun4m_smp.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sparc/kernel/sun4m_smp.c	Sat Apr  3 19:38:55 2004
@@ -15,6 +15,9 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
 
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
@@ -26,16 +29,13 @@
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
 #include <asm/hardirq.h>
-
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
+#include <asm/cpudata.h>
 
 #define IRQ_RESCHEDULE		13
 #define IRQ_STOP_CPU		14
 #define IRQ_CROSS_CALL		15
 
 extern ctxd_t *srmmu_ctx_table_phys;
-extern int linux_num_cpus;
 
 extern void calibrate_delay(void);
 
@@ -43,11 +43,7 @@
 extern unsigned long cpu_present_map;
 extern int smp_num_cpus;
 extern int smp_threads_ready;
-extern unsigned char mid_xlate[NR_CPUS];
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
-extern unsigned long smp_proc_in_lock[NR_CPUS];
-extern struct cpuinfo_sparc cpu_data[NR_CPUS];
-extern unsigned long cpu_offset[NR_CPUS];
 extern unsigned char boot_cpu_id;
 extern int smp_activated;
 extern volatile int __cpu_number_map[NR_CPUS];
@@ -83,7 +79,7 @@
 	local_flush_cache_all();
 	local_flush_tlb_all();
 
-	set_irq_udt(mid_xlate[boot_cpu_id]);
+	set_irq_udt(boot_cpu_id);
 
 	/* Get our local ticker going. */
 	smp_setup_percpu_timer();
@@ -137,7 +133,6 @@
  *	Cycle through the processors asking the PROM to start each one.
  */
  
-extern struct prom_cpuinfo linux_cpus[NR_CPUS];
 extern struct linux_prom_registers smp_penguin_ctable;
 extern unsigned long trapbase_cpu1[];
 extern unsigned long trapbase_cpu2[];
@@ -146,33 +141,30 @@
 void __init smp4m_boot_cpus(void)
 {
 	int cpucount = 0;
-	int i = 0;
-	int first, prev;
+	int i, mid;
 
 	printk("Entering SMP Mode...\n");
 
 	local_irq_enable();
 	cpu_present_map = 0;
 
-	for(i=0; i < linux_num_cpus; i++)
-		cpu_present_map |= (1<<i);
+	for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
+		cpu_present_map |= (1<<mid);
 
 	for(i=0; i < NR_CPUS; i++) {
-		cpu_offset[i] = (char *)&cpu_data[i] - (char *)&cpu_data;
 		__cpu_number_map[i] = -1;
 		__cpu_logical_map[i] = -1;
 	}
 
-	mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
 	__cpu_number_map[boot_cpu_id] = 0;
 	__cpu_logical_map[0] = boot_cpu_id;
-	current->cpu = boot_cpu_id;
+	current_thread_info()->cpu = boot_cpu_id;
 
 	smp_store_cpu_info(boot_cpu_id);
-	set_irq_udt(mid_xlate[boot_cpu_id]);
+	set_irq_udt(boot_cpu_id);
 	smp_setup_percpu_timer();
 	local_flush_cache_all();
-	if(linux_num_cpus == 1)
+	if(cpu_find_by_instance(1, NULL, NULL))
 		return;  /* Not an MP box. */
 	for(i = 0; i < NR_CPUS; i++) {
 		if(i == boot_cpu_id)
@@ -191,9 +183,9 @@
 
 			p = prev_task(&init_task);
 
-			p->cpu = i;
+			init_idle(p, i);
 
-			current_set[i] = p;
+			current_set[i] = p->thread_info;
 
 			unhash_process(p);
 
@@ -211,9 +203,8 @@
 
 			/* whirrr, whirrr, whirrrrrrrrr... */
 			printk("Starting CPU %d at %p\n", i, entry);
-			mid_xlate[i] = (linux_cpus[i].mid & ~8);
 			local_flush_cache_all();
-			prom_startcpu(linux_cpus[i].prom_node,
+			prom_startcpu(cpu_data(i).prom_node,
 				      &smp_penguin_ctable, 0, (char *)entry);
 
 			/* wheee... it's going... */
@@ -244,7 +235,7 @@
 		unsigned long bogosum = 0;
 		for(i = 0; i < NR_CPUS; i++) {
 			if(cpu_present_map & (1 << i))
-				bogosum += cpu_data[i].udelay_val;
+				bogosum += cpu_data(i).udelay_val;
 		}
 		printk("Total of %d Processors activated (%lu.%02lu BogoMIPS).\n",
 		       cpucount + 1,
@@ -254,20 +245,6 @@
 		smp_num_cpus = cpucount + 1;
 	}
 
-	/* Setup CPU list for IRQ distribution scheme. */
-	first = prev = -1;
-	for(i = 0; i < NR_CPUS; i++) {
-		if(cpu_present_map & (1 << i)) {
-			if(first == -1)
-				first = i;
-			if(prev != -1)
-				cpu_data[prev].next = i;
-			cpu_data[i].mid = mid_xlate[i];
-			prev = i;
-		}
-	}
-	cpu_data[prev].next = first;
-	
 	/* Free unneeded trap tables */
 	if (!(cpu_present_map & (1 << 1))) {
 		ClearPageReserved(virt_to_page(trapbase_cpu1));
@@ -298,11 +275,11 @@
 /* At each hardware IRQ, we get this called to forward IRQ reception
  * to the next processor.  The caller must disable the IRQ level being
  * serviced globally so that there are no double interrupts received.
+ *
+ * XXX See sparc64 irq.c.
  */
 void smp4m_irq_rotate(int cpu)
 {
-	if(smp_processors_ready)
-		set_irq_udt(cpu_data[cpu_data[cpu].next].mid);
 }
 
 /* Cross calls, in order to work efficiently and atomically do all
@@ -334,10 +311,10 @@
 			mask &= ~(1 << me);
 		for(i = 0; i < 4; i++) {
 			if(mask & (1 << i))
-				set_cpu_int(mid_xlate[i], irq);
+				set_cpu_int(i, irq);
 		}
 	} else {
-		set_cpu_int(mid_xlate[target], irq);
+		set_cpu_int(target, irq);
 	}
 	smp_cpu_in_msg[me]--;
 
@@ -388,7 +365,7 @@
 				if(mask & (1 << i)) {
 					ccall_info.processors_in[i] = 0;
 					ccall_info.processors_out[i] = 0;
-					set_cpu_int(mid_xlate[i], IRQ_CROSS_CALL);
+					set_cpu_int(i, IRQ_CROSS_CALL);
 				} else {
 					ccall_info.processors_in[i] = 1;
 					ccall_info.processors_out[i] = 1;
@@ -427,28 +404,25 @@
 	ccall_info.processors_out[i] = 1;
 }
 
-extern unsigned int prof_multiplier[NR_CPUS];
-extern unsigned int prof_counter[NR_CPUS];
-
 extern void sparc_do_profile(unsigned long pc, unsigned long o7);
 
 void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 
-	clear_profile_irq(mid_xlate[cpu]);
+	clear_profile_irq(cpu);
 
 	if(!user_mode(regs))
 		sparc_do_profile(regs->pc, regs->u_regs[UREG_RETPC]);
 
-	if(!--prof_counter[cpu]) {
+	if(!--prof_counter(cpu)) {
 		int user = user_mode(regs);
 
 		irq_enter();
 		update_process_times(user);
 		irq_exit();
 
-		prof_counter[cpu] = prof_multiplier[cpu];
+		prof_counter(cpu) = prof_multiplier(cpu);
 	}
 }
 
@@ -458,8 +432,8 @@
 {
 	int cpu = smp_processor_id();
 
-	prof_counter[cpu] = prof_multiplier[cpu] = 1;
-	load_profile_irq(mid_xlate[cpu], lvl14_resolution);
+	prof_counter(cpu) = prof_multiplier(cpu) = 1;
+	load_profile_irq(cpu, lvl14_resolution);
 
 	if(cpu == boot_cpu_id)
 		enable_pil_irq(14);
diff -Nru a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
--- a/arch/sparc/kernel/sys_sunos.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc/kernel/sys_sunos.c	Sat Apr  3 19:38:43 2004
@@ -343,7 +343,7 @@
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *)dirent + reclen;
 	buf->curr = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -422,7 +422,7 @@
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *)dirent + reclen;
 	buf->curr = dirent;
 	buf->count -= reclen;
 	return 0;
diff -Nru a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
--- a/arch/sparc/kernel/traps.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc/kernel/traps.c	Sat Apr  3 19:38:43 2004
@@ -131,23 +131,23 @@
 	do_exit(SIGSEGV);
 }
 
-void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
+void do_hw_interrupt(struct pt_regs *regs, unsigned long type)
 {
 	siginfo_t info;
 
 	if(type < 0x80) {
 		/* Sun OS's puke from bad traps, Linux survives! */
 		printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
-		die_if_kernel("Whee... Hello Mr. Penguin", current->thread.kregs);
+		die_if_kernel("Whee... Hello Mr. Penguin", regs);
 	}	
 
-	if(psr & PSR_PS)
-		die_if_kernel("Kernel bad trap", current->thread.kregs);
+	if(regs->psr & PSR_PS)
+		die_if_kernel("Kernel bad trap", regs);
 
 	info.si_signo = SIGILL;
 	info.si_errno = 0;
 	info.si_code = ILL_ILLTRP;
-	info.si_addr = (void *)pc;
+	info.si_addr = (void *)regs->pc;
 	info.si_trapno = type - 0x80;
 	force_sig_info(SIGILL, &info, current);
 }
diff -Nru a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
--- a/arch/sparc/lib/Makefile	Sat Apr  3 19:38:56 2004
+++ b/arch/sparc/lib/Makefile	Sat Apr  3 19:38:56 2004
@@ -7,5 +7,7 @@
 lib-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \
          strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \
 	 strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
-	 copy_user.o locks.o atomic.o atomic32.o bitops.o debuglocks.o \
+	 copy_user.o locks.o atomic.o atomic32.o bitops.o \
 	 lshrdi3.o ashldi3.o rwsem.o muldi3.o bitext.o
+
+lib-$(CONFIG_DEBUG_SPINLOCK) +=	debuglocks.o
diff -Nru a/arch/sparc/lib/debuglocks.c b/arch/sparc/lib/debuglocks.c
--- a/arch/sparc/lib/debuglocks.c	Sat Apr  3 19:38:41 2004
+++ b/arch/sparc/lib/debuglocks.c	Sat Apr  3 19:38:41 2004
@@ -12,8 +12,7 @@
 #include <asm/psr.h>
 #include <asm/system.h>
 
-/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */
-#ifdef SPIN_LOCK_DEBUG
+#ifdef CONFIG_SMP
 
 /* Some notes on how these debugging routines work.  When a lock is acquired
  * an extra debugging member lock->owner_pc is set to the caller of the lock
@@ -200,4 +199,4 @@
 	rw->lock = 0;
 }
 
-#endif /* SPIN_LOCK_DEBUG */
+#endif /* SMP */
diff -Nru a/arch/sparc/math-emu/math.c b/arch/sparc/math-emu/math.c
--- a/arch/sparc/math-emu/math.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc/math-emu/math.c	Sat Apr  3 19:38:43 2004
@@ -327,6 +327,7 @@
 #ifdef DEBUG_MATHEMU
 			printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff);
 #endif
+			break;
 		}
 	} else if ((insn & 0xc1f80000) == 0x81a80000)	/* FPOP2 */ {
 		switch ((insn >> 5) & 0x1ff) {
@@ -340,6 +341,7 @@
 #ifdef DEBUG_MATHEMU
 			printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff);
 #endif
+			break;
 		}
 	}
 
diff -Nru a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
--- a/arch/sparc/mm/init.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc/mm/init.c	Sat Apr  3 19:38:43 2004
@@ -38,6 +38,7 @@
 unsigned long *sparc_valid_addr_bitmap;
 
 unsigned long phys_base;
+unsigned long pfn_base;
 
 unsigned long page_kernel;
 
@@ -134,7 +135,7 @@
 unsigned long calc_max_low_pfn(void)
 {
 	int i;
-	unsigned long tmp = (SRMMU_MAXMEM >> PAGE_SHIFT);
+	unsigned long tmp = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
 	unsigned long curr_pfn, last_pfn;
 
 	last_pfn = (sp_banks[0].base_addr + sp_banks[0].num_bytes) >> PAGE_SHIFT;
@@ -189,9 +190,6 @@
 	 */
 	start_pfn  = (unsigned long)__pa(PAGE_ALIGN((unsigned long) &_end));
 
-	/* Adjust up to the physical address where the kernel begins. */
-	start_pfn += phys_base;
-
 	/* Now shift down to get the real physical page frame number. */
 	start_pfn >>= PAGE_SHIFT;
 
@@ -202,8 +200,8 @@
 	max_low_pfn = max_pfn;
 	highstart_pfn = highend_pfn = max_pfn;
 
-	if (max_low_pfn > (SRMMU_MAXMEM >> PAGE_SHIFT)) {
-		highstart_pfn = (SRMMU_MAXMEM >> PAGE_SHIFT);
+	if (max_low_pfn > pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT)) {
+		highstart_pfn = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
 		max_low_pfn = calc_max_low_pfn();
 		printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
 		    calc_highpages() >> (20 - PAGE_SHIFT));
@@ -230,7 +228,8 @@
 	}
 #endif	
 	/* Initialize the boot-time allocator. */
-	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, phys_base>>PAGE_SHIFT, max_low_pfn);
+	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, pfn_base,
+					 max_low_pfn);
 
 	/* Now register the available physical memory with the
 	 * allocator.
@@ -267,8 +266,8 @@
 		reserve_bootmem(initrd_start, size);
 		*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
-		initrd_start += PAGE_OFFSET;
-		initrd_end += PAGE_OFFSET;
+		initrd_start = (initrd_start - phys_base) + PAGE_OFFSET;
+		initrd_end = (initrd_end - phys_base) + PAGE_OFFSET;		
 	}
 #endif
 	/* Reserve the kernel text/data/bss. */
@@ -432,7 +431,7 @@
 
 	taint_real_pages();
 
-	max_mapnr = last_valid_pfn - (phys_base >> PAGE_SHIFT);
+	max_mapnr = last_valid_pfn - pfn_base;
 	high_memory = __va(max_low_pfn << PAGE_SHIFT);
 
 	num_physpages = totalram_pages = free_all_bootmem();
@@ -474,11 +473,9 @@
 
 	addr = (unsigned long)(&__init_begin);
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-		unsigned long page;
 		struct page *p;
 
-		page = addr + phys_base;
-		p = virt_to_page(page);
+		p = virt_to_page(addr);
 
 		ClearPageReserved(p);
 		set_page_count(p, 1);
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Sat Apr  3 19:38:44 2004
+++ b/arch/sparc/mm/srmmu.c	Sat Apr  3 19:38:44 2004
@@ -213,7 +213,7 @@
  * and a page entry and page directory to the page they refer to.
  */
 static pte_t srmmu_mk_pte(struct page *page, pgprot_t pgprot)
-{ return __pte(((page - mem_map) << (PAGE_SHIFT-4)) | pgprot_val(pgprot)); }
+{ return __pte((page_to_pfn(page) << (PAGE_SHIFT-4)) | pgprot_val(pgprot)); }
 
 static pte_t srmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot)
 { return __pte(((page) >> 4) | pgprot_val(pgprot)); }
@@ -245,7 +245,7 @@
 	unsigned long ptp;	/* Physical address, shifted right by 4 */
 	int i;
 
-	ptp = (ptep - mem_map) << (PAGE_SHIFT-4);	/* watch for overflow */
+	ptp = page_to_pfn(ptep) << (PAGE_SHIFT-4);	/* watch for overflow */
 	for (i = 0; i < SRMMU_PTRS_PER_PTE_SOFT/SRMMU_PTRS_PER_PTE; i++) {
 		srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp);
 		ptp += (SRMMU_PTRS_PER_PTE*sizeof(pte_t) >> 4);
@@ -480,7 +480,7 @@
 
 	if ((pte = (unsigned long)srmmu_pte_alloc_one_kernel(mm, address)) == 0)
 		return NULL;
-	return mem_map + (__nocache_pa(pte) >> PAGE_SHIFT);
+	return pfn_to_page( __nocache_pa(pte) >> PAGE_SHIFT );
 }
 
 static void srmmu_free_pte_fast(pte_t *pte)
@@ -495,7 +495,7 @@
 	p = (unsigned long)page_address(pte);	/* Cached address (for test) */
 	if (p == 0)
 		BUG();
-	p = ((pte - mem_map) << PAGE_SHIFT);	/* Physical address */
+	p = page_to_pfn(pte) << PAGE_SHIFT;	/* Physical address */
 	p = (unsigned long) __nocache_va(p);	/* Nocached virtual */
 	srmmu_free_nocache(p, SRMMU_PTE_SZ_SOFT);
 }
@@ -1230,8 +1230,6 @@
 /* Paging initialization on the Sparc Reference MMU. */
 extern void sparc_context_init(int);
 
-extern int linux_num_cpus;
-
 void (*poke_srmmu)(void) __initdata = NULL;
 
 extern unsigned long bootmem_init(unsigned long *pages_avail);
@@ -1318,7 +1316,7 @@
 		for (znum = 0; znum < MAX_NR_ZONES; znum++)
 			zones_size[znum] = zholes_size[znum] = 0;
 
-		npages = max_low_pfn - (phys_base >> PAGE_SHIFT);
+		npages = max_low_pfn - pfn_base;
 
 		zones_size[ZONE_DMA] = npages;
 		zholes_size[ZONE_DMA] = npages - pages_avail;
@@ -1328,13 +1326,9 @@
 		zholes_size[ZONE_HIGHMEM] = npages - calc_highpages();
 
 		free_area_init_node(0, &contig_page_data, NULL, zones_size,
-				    phys_base >> PAGE_SHIFT, zholes_size);
+				    pfn_base, zholes_size);
 		mem_map = contig_page_data.node_mem_map;
 	}
-
-/* P3: easy to fix, todo. Current code is utterly broken, though. */
-	if (phys_base != 0)
-		panic("phys_base nonzero");
 }
 
 static void srmmu_mmu_info(struct seq_file *m)
diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c	Sat Apr  3 19:38:54 2004
+++ b/arch/sparc/mm/sun4c.c	Sat Apr  3 19:38:54 2004
@@ -2088,7 +2088,7 @@
 		for (znum = 0; znum < MAX_NR_ZONES; znum++)
 			zones_size[znum] = zholes_size[znum] = 0;
 
-		npages = max_low_pfn - (phys_base >> PAGE_SHIFT);
+		npages = max_low_pfn - pfn_base;
 
 		zones_size[ZONE_DMA] = npages;
 		zholes_size[ZONE_DMA] = npages - pages_avail;
@@ -2098,7 +2098,7 @@
 		zholes_size[ZONE_HIGHMEM] = npages - calc_highpages();
 
 		free_area_init_node(0, &contig_page_data, NULL, zones_size,
-				    phys_base >> PAGE_SHIFT, zholes_size);
+				    pfn_base, zholes_size);
 		mem_map = contig_page_data.node_mem_map;
 	}
 
diff -Nru a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
--- a/arch/sparc64/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/sparc64/Kconfig	Sat Apr  3 19:38:55 2004
@@ -107,8 +107,8 @@
 	  Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
 	  Management" code will be disabled if you say Y here.
 
-	  See also the <file:Documentation/smp.tex>,
-	  <file:Documentation/smp.txt>, <file:Documentation/i386/IO-APIC.txt>,
+	  See also the <file:Documentation/smp.txt>,
+	  <file:Documentation/i386/IO-APIC.txt>,
 	  <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
 	  <http://www.tldp.org/docs.html#howto>.
 
@@ -139,7 +139,7 @@
 	  fly.  Currently there are only sparc64 drivers for UltraSPARC-III
 	  and UltraSPARC-IIe processors.
 
-	  For details, take a look at linux/Documentation/cpufreq. 
+	  For details, take a look at linux/Documentation/cpu-freq.
 
 	  If in doubt, say N.
 
@@ -159,7 +159,7 @@
 	help
 	  This adds the CPUFreq driver for UltraSPARC-III processors.
 
-	  For details, take a look at linux/Documentation/cpufreq. 
+	  For details, take a look at linux/Documentation/cpu-freq.
 
 	  If in doubt, say N.
 
@@ -169,7 +169,7 @@
 	help
 	  This adds the CPUFreq driver for UltraSPARC-IIe processors.
 
-	  For details, take a look at linux/Documentation/cpufreq. 
+	  For details, take a look at linux/Documentation/cpu-freq.
 
 	  If in doubt, say N.
 
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Sat Apr  3 19:38:42 2004
+++ b/arch/sparc64/defconfig	Sat Apr  3 19:38:42 2004
@@ -39,6 +39,7 @@
 CONFIG_OBSOLETE_MODPARM=y
 CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
 
 #
 # General setup
@@ -112,7 +113,8 @@
 # Graphics support
 #
 CONFIG_FB=y
-# CONFIG_FB_PM2 is not set
+CONFIG_FB_PM2=y
+# CONFIG_FB_PM2_FIFO_DISCONNECT is not set
 # CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_BW2 is not set
@@ -123,7 +125,10 @@
 # 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_ATY=y
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_XL_INIT is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
 # CONFIG_FB_KYRO is not set
@@ -209,8 +214,8 @@
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_CRYPTOLOOP=m
 CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_CARMEL=m
 # CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -261,7 +266,9 @@
 CONFIG_BLK_DEV_PIIX=m
 CONFIG_BLK_DEV_NS87415=m
 CONFIG_BLK_DEV_PDC202XX_OLD=m
+# CONFIG_PDC202XX_BURST is not set
 CONFIG_BLK_DEV_PDC202XX_NEW=m
+# CONFIG_PDC202XX_FORCE is not set
 CONFIG_BLK_DEV_SVWKS=m
 CONFIG_BLK_DEV_SIIMAGE=m
 CONFIG_BLK_DEV_SLC90E66=m
@@ -270,7 +277,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -298,6 +304,12 @@
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_ATTRS=m
+
+#
 # SCSI low-level drivers
 #
 CONFIG_BLK_DEV_3W_XXXX_RAID=m
@@ -319,7 +331,9 @@
 CONFIG_SCSI_SATA_SVW=m
 CONFIG_SCSI_ATA_PIIX=m
 CONFIG_SCSI_SATA_PROMISE=m
+CONFIG_SCSI_SATA_SIL=m
 CONFIG_SCSI_SATA_VIA=m
+CONFIG_SCSI_SATA_VITESSE=m
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 CONFIG_SCSI_DMX3191D=m
@@ -384,7 +398,6 @@
 CONFIG_MD_RAID6=m
 CONFIG_MD_MULTIPATH=m
 CONFIG_BLK_DEV_DM=m
-# CONFIG_DM_IOCTL_V4 is not set
 CONFIG_DM_CRYPT=m
 
 #
@@ -451,7 +464,6 @@
 CONFIG_IP_PIMSM_V1=y
 CONFIG_IP_PIMSM_V2=y
 CONFIG_ARPD=y
-CONFIG_INET_ECN=y
 CONFIG_SYN_COOKIES=y
 CONFIG_INET_AH=y
 CONFIG_INET_ESP=y
@@ -619,7 +631,6 @@
 #
 # SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=m
 CONFIG_IP_SCTP=m
 # CONFIG_SCTP_DBG_MSG is not set
 # CONFIG_SCTP_DBG_OBJCNT is not set
@@ -664,6 +675,7 @@
 CONFIG_NET_SCH_TBF=m
 CONFIG_NET_SCH_GRED=m
 CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_DELAY=m
 CONFIG_NET_SCH_INGRESS=m
 CONFIG_NET_QOS=y
 CONFIG_NET_ESTIMATOR=y
@@ -812,6 +824,11 @@
 CONFIG_PCI_HERMES=m
 CONFIG_ATMEL=m
 CONFIG_PCI_ATMEL=m
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
 CONFIG_NET_WIRELESS=y
 
 #
@@ -820,6 +837,7 @@
 # CONFIG_TR is not set
 CONFIG_NET_FC=y
 CONFIG_SHAPER=m
+CONFIG_NETCONSOLE=m
 
 #
 # Wan interfaces
@@ -944,6 +962,10 @@
 CONFIG_BT_HCIBCM203X=m
 CONFIG_BT_HCIBFUSB=m
 CONFIG_BT_HCIVHCI=m
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
 
 #
 # ISDN subsystem
@@ -1044,11 +1066,13 @@
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 CONFIG_KEYBOARD_SUNKBD=y
+CONFIG_KEYBOARD_LKKBD=m
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 CONFIG_MOUSE_SERIAL=y
+CONFIG_MOUSE_VSXXXAA=m
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
@@ -1075,12 +1099,10 @@
 CONFIG_I2C_ALI15X3=m
 CONFIG_I2C_AMD756=m
 CONFIG_I2C_AMD8111=m
-CONFIG_I2C_ELV=m
 CONFIG_I2C_I801=m
 CONFIG_I2C_I810=m
 CONFIG_I2C_ISA=m
 CONFIG_I2C_NFORCE2=m
-CONFIG_I2C_PHILIPSPAR=m
 CONFIG_I2C_PARPORT=m
 CONFIG_I2C_PARPORT_LIGHT=m
 CONFIG_I2C_PROSAVAGE=m
@@ -1089,30 +1111,37 @@
 CONFIG_I2C_SIS5595=m
 CONFIG_I2C_SIS630=m
 CONFIG_I2C_SIS96X=m
-CONFIG_I2C_VELLEMAN=m
 CONFIG_I2C_VIA=m
 CONFIG_I2C_VIAPRO=m
 CONFIG_I2C_VOODOO3=m
 
 #
-# I2C Hardware Sensors Chip support
+# Hardware Sensors Chip support
 #
 CONFIG_I2C_SENSOR=m
 CONFIG_SENSORS_ADM1021=m
 CONFIG_SENSORS_ASB100=m
-CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_DS1621=m
 CONFIG_SENSORS_FSCHER=m
 CONFIG_SENSORS_GL518SM=m
 CONFIG_SENSORS_IT87=m
 CONFIG_SENSORS_LM75=m
 CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
 CONFIG_SENSORS_LM83=m
 CONFIG_SENSORS_LM85=m
 CONFIG_SENSORS_LM90=m
 CONFIG_SENSORS_VIA686A=m
 CONFIG_SENSORS_W83781D=m
 CONFIG_SENSORS_W83L785TS=m
+CONFIG_SENSORS_W83627HF=m
+
+#
+# Other I2C Chip support
+#
+CONFIG_SENSORS_EEPROM=m
 # CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 
@@ -1174,7 +1203,7 @@
 # CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS_XATTR=y
 # CONFIG_DEVPTS_FS_SECURITY is not set
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
 CONFIG_HUGETLBFS=y
 CONFIG_HUGETLB_PAGE=y
 CONFIG_RAMFS=y
@@ -1231,6 +1260,7 @@
 # CONFIG_NCPFS_EXTRAS is not set
 CONFIG_CODA_FS=m
 # CONFIG_CODA_FS_OLD_API is not set
+CONFIG_INTERMEZZO_FS=m
 CONFIG_AFS_FS=m
 CONFIG_RXRPC=m
 
@@ -1391,6 +1421,10 @@
 #
 CONFIG_SND=m
 CONFIG_SND_BIT32_EMUL=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
 CONFIG_SND_SEQUENCER=m
 CONFIG_SND_SEQ_DUMMY=m
 CONFIG_SND_OSSEMUL=y
@@ -1404,6 +1438,9 @@
 #
 # Generic devices
 #
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_VX_LIB=m
 CONFIG_SND_DUMMY=m
 CONFIG_SND_VIRMIDI=m
 # CONFIG_SND_MTPAV is not set
@@ -1413,7 +1450,12 @@
 #
 # PCI devices
 #
+CONFIG_SND_AC97_CODEC=m
 CONFIG_SND_ALI5451=m
+CONFIG_SND_ATIIXP=m
+CONFIG_SND_AU8810=m
+CONFIG_SND_AU8820=m
+CONFIG_SND_AU8830=m
 CONFIG_SND_AZT3328=m
 CONFIG_SND_BT87X=m
 CONFIG_SND_CS46XX=m
@@ -1421,6 +1463,7 @@
 CONFIG_SND_CS4281=m
 CONFIG_SND_EMU10K1=m
 CONFIG_SND_KORG1212=m
+CONFIG_SND_MIXART=m
 CONFIG_SND_NM256=m
 # CONFIG_SND_RME32 is not set
 # CONFIG_SND_RME96 is not set
@@ -1436,9 +1479,11 @@
 CONFIG_SND_ES1968=m
 CONFIG_SND_MAESTRO3=m
 CONFIG_SND_FM801=m
+CONFIG_SND_FM801_TEA575X=m
 CONFIG_SND_ICE1712=m
 # CONFIG_SND_ICE1724 is not set
 CONFIG_SND_INTEL8X0=m
+CONFIG_SND_INTEL8X0M=m
 CONFIG_SND_SONICVIBES=m
 # CONFIG_SND_VIA82XX is not set
 CONFIG_SND_VX222=m
@@ -1476,6 +1521,7 @@
 # USB Host Controller Drivers
 #
 CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_UHCI_HCD=m
 
@@ -1512,7 +1558,9 @@
 CONFIG_USB_WACOM=m
 CONFIG_USB_KBTAB=m
 # CONFIG_USB_POWERMATE is not set
+CONFIG_USB_MTOUCH=m
 # CONFIG_USB_XPAD is not set
+CONFIG_USB_ATI_REMOTE=m
 
 #
 # USB Imaging devices
@@ -1547,6 +1595,7 @@
 #
 # USB Host-to-Host Cables
 #
+CONFIG_USB_ALI_M5632=y
 CONFIG_USB_AN2720=y
 CONFIG_USB_BELKIN=y
 CONFIG_USB_GENESYS=y
@@ -1618,7 +1667,6 @@
 CONFIG_USB_AUERSWALD=m
 CONFIG_USB_RIO500=m
 CONFIG_USB_LEGOTOWER=m
-# CONFIG_USB_BRLVGER is not set
 CONFIG_USB_LCD=m
 CONFIG_USB_LED=m
 CONFIG_USB_SPEEDTOUCH=m
@@ -1701,6 +1749,7 @@
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_TEST=m
 
 #
diff -Nru a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
--- a/arch/sparc64/kernel/entry.S	Sat Apr  3 19:38:40 2004
+++ b/arch/sparc64/kernel/entry.S	Sat Apr  3 19:38:40 2004
@@ -26,7 +26,7 @@
 
 #define curptr      g6
 
-#define NR_SYSCALLS 272      /* Each OS is different... */
+#define NR_SYSCALLS 273      /* Each OS is different... */
 
 	.text
 	.align		32
diff -Nru a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
--- a/arch/sparc64/kernel/init_task.c	Sat Apr  3 19:38:56 2004
+++ b/arch/sparc64/kernel/init_task.c	Sat Apr  3 19:38:56 2004
@@ -24,14 +24,6 @@
 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 -Nru a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
--- a/arch/sparc64/kernel/pci_iommu.c	Sat Apr  3 19:38:41 2004
+++ b/arch/sparc64/kernel/pci_iommu.c	Sat Apr  3 19:38:41 2004
@@ -352,8 +352,7 @@
 
 bad:
 	spin_unlock_irqrestore(&iommu->lock, flags);
-	BUG();
-	return 0;
+	return PCI_DMA_ERROR_CODE;
 }
 
 /* Unmap a single streaming mode DMA translation. */
@@ -580,8 +579,7 @@
 
 bad:
 	spin_unlock_irqrestore(&iommu->lock, flags);
-	BUG();
-	return 0;
+	return PCI_DMA_ERROR_CODE;
 }
 
 /* Unmap a set of streaming mode DMA translations. */
@@ -661,7 +659,7 @@
 /* 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 +720,7 @@
 /* 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 -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc64/kernel/process.c	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
--- a/arch/sparc64/kernel/sbus.c	Sat Apr  3 19:38:56 2004
+++ b/arch/sparc64/kernel/sbus.c	Sat Apr  3 19:38:56 2004
@@ -540,7 +540,7 @@
 	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 @@
 	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;
@@ -570,6 +574,10 @@
 	spin_lock_irqsave(&iommu->lock, flags);
 	strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT);
 	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. */
diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
--- a/arch/sparc64/kernel/setup.c	Sat Apr  3 19:38:42 2004
+++ b/arch/sparc64/kernel/setup.c	Sat Apr  3 19:38:42 2004
@@ -603,11 +603,6 @@
 }
 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 -Nru a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
--- a/arch/sparc64/kernel/signal32.c	Sat Apr  3 19:38:40 2004
+++ b/arch/sparc64/kernel/signal32.c	Sat Apr  3 19:38:40 2004
@@ -394,7 +394,7 @@
 asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
 {
 	struct rt_signal_frame32 __user *sf;
-	unsigned int psr, pc, npc, fpu_save;
+	unsigned int psr, pc, npc, fpu_save, u_ss_sp;
 	mm_segment_t old_fs;
 	sigset_t set;
 	compat_sigset_t seta;
@@ -448,7 +448,8 @@
 	if (fpu_save)
 		err |= restore_fpu_state32(regs, &sf->fpu_state);
 	err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
-	err |= __get_user((long)st.ss_sp, &sf->stack.ss_sp);
+	err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
+	st.ss_sp = (void *) (long) u_ss_sp;
 	err |= __get_user(st.ss_flags, &sf->stack.ss_flags);
 	err |= __get_user(st.ss_size, &sf->stack.ss_size);
 	if (err)
@@ -977,7 +978,7 @@
 {
 	svr4_gregset_t  __user *gr;
 	mm_segment_t old_fs;
-	u32 pc, npc, psr;
+	u32 pc, npc, psr, u_ss_sp;
 	sigset_t set;
 	svr4_sigset_t setv;
 	int i, err;
@@ -1017,7 +1018,8 @@
 	if (_NSIG_WORDS >= 2)
 		set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32);
 	
-	err |= __get_user((long)st.ss_sp, &c->stack.sp);
+	err |= __get_user(u_ss_sp, &c->stack.sp);
+	st.ss_sp = (void *) (long) u_ss_sp;
 	err |= __get_user(st.ss_flags, &c->stack.flags);
 	err |= __get_user(st.ss_size, &c->stack.size);
 	if (err)
@@ -1310,9 +1312,9 @@
 	
 	/* Now see if we want to update the new state. */
 	if (ssptr) {
-		void *ss_sp;
+		u32 ss_sp;
 
-		if (get_user((long)ss_sp, &ssptr->the_stack))
+		if (get_user(ss_sp, &ssptr->the_stack))
 			goto out;
 
 		/* If the current stack was set with sigaltstack, don't
@@ -1338,13 +1340,15 @@
 asmlinkage int do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp)
 {
 	stack_t uss, uoss;
+	u32 u_ss_sp = 0;
 	int ret;
 	mm_segment_t old_fs;
 	
-	if (ussa && (get_user((long)uss.ss_sp, &((stack_t32 __user *)(long)ussa)->ss_sp) ||
+	if (ussa && (get_user(u_ss_sp, &((stack_t32 __user *)(long)ussa)->ss_sp) ||
 		    __get_user(uss.ss_flags, &((stack_t32 __user *)(long)ussa)->ss_flags) ||
 		    __get_user(uss.ss_size, &((stack_t32 __user *)(long)ussa)->ss_size)))
 		return -EFAULT;
+	uss.ss_sp = (void *) (long) u_ss_sp;
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
 	ret = do_sigaltstack(ussa ? &uss : NULL, uossa ? &uoss : NULL, sp);
diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
--- a/arch/sparc64/kernel/smp.c	Sat Apr  3 19:38:40 2004
+++ b/arch/sparc64/kernel/smp.c	Sat Apr  3 19:38:40 2004
@@ -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 -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Sat Apr  3 19:38:55 2004
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Sat Apr  3 19:38:55 2004
@@ -91,6 +91,7 @@
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
 extern long sparc32_open(const char * filename, int flags, int mode);
 extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space);
+extern void (*prom_palette)(int);
 
 extern int __ashrdi3(int, int);
 
@@ -213,8 +214,10 @@
 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);
 #endif
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(outsw);
@@ -232,8 +235,8 @@
 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
 
@@ -386,3 +389,5 @@
 EXPORT_SYMBOL(xor_vis_3);
 EXPORT_SYMBOL(xor_vis_4);
 EXPORT_SYMBOL(xor_vis_5);
+
+EXPORT_SYMBOL(prom_palette);
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 19:38:44 2004
+++ b/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 19:38:44 2004
@@ -27,9 +27,6 @@
 #include <linux/slab.h>
 #include <linux/uio.h>
 #include <linux/nfs_fs.h>
-#include <linux/smb_fs.h>
-#include <linux/smb_mount.h>
-#include <linux/ncp_fs.h>
 #include <linux/quota.h>
 #include <linux/module.h>
 #include <linux/sunrpc/svc.h>
@@ -282,11 +279,6 @@
 		 __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
@@ -1094,7 +1086,7 @@
 {
 	struct linux_dirent32 * dirent;
 	struct getdents_callback32 * buf = (struct getdents_callback32 *) __buf;
-	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
 
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
@@ -1108,7 +1100,8 @@
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	put_user(d_type, (char *) dirent + reclen - 1);
+	dirent = (void *) dirent + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -1334,209 +1327,6 @@
 	return sys_sysfs(option, arg1, arg2);
 }
 
-struct ncp_mount_data32_v3 {
-        int version;
-        unsigned int ncp_fd;
-        compat_uid_t mounted_uid;
-        compat_pid_t wdog_pid;
-        unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
-        unsigned int time_out;
-        unsigned int retry_count;
-        unsigned int flags;
-        compat_uid_t uid;
-        compat_gid_t gid;
-        compat_mode_t file_mode;
-        compat_mode_t dir_mode;
-};
-
-struct ncp_mount_data32_v4 {
-	int version;
-	/* all members below are "long" in ABI ... i.e. 32bit on sparc32, while 64bits on sparc64 */
-	unsigned int flags;
-	unsigned int mounted_uid;
-	int wdog_pid;
-
-	unsigned int ncp_fd;
-	unsigned int time_out;
-	unsigned int retry_count;
-
-	unsigned int uid;
-	unsigned int gid;
-	unsigned int file_mode;
-	unsigned int dir_mode;
-};
-
-static void *do_ncp_super_data_conv(void *raw_data)
-{
-	switch (*(int*)raw_data) {
-		case NCP_MOUNT_VERSION:
-			{
-				struct ncp_mount_data news, *n = &news; 
-				struct ncp_mount_data32_v3 *n32 = (struct ncp_mount_data32_v3 *)raw_data;
-
-				n->version = n32->version;
-				n->ncp_fd = n32->ncp_fd;
-				n->mounted_uid = low2highuid(n32->mounted_uid);
-				n->wdog_pid = n32->wdog_pid;
-				memmove (n->mounted_vol, n32->mounted_vol, sizeof (n32->mounted_vol));
-				n->time_out = n32->time_out;
-				n->retry_count = n32->retry_count;
-				n->flags = n32->flags;
-				n->uid = low2highuid(n32->uid);
-				n->gid = low2highgid(n32->gid);
-				n->file_mode = n32->file_mode;
-				n->dir_mode = n32->dir_mode;
-				memcpy(raw_data, n, sizeof(*n)); 
-			}
-			break;
-		case NCP_MOUNT_VERSION_V4:
-			{
-				struct ncp_mount_data_v4 news, *n = &news; 
-				struct ncp_mount_data32_v4 *n32 = (struct ncp_mount_data32_v4 *)raw_data;
-
-				n->version = n32->version;
-				n->flags = n32->flags;
-				n->mounted_uid = n32->mounted_uid;
-				n->wdog_pid = n32->wdog_pid;
-				n->ncp_fd = n32->ncp_fd;
-				n->time_out = n32->time_out;
-				n->retry_count = n32->retry_count;
-				n->uid = n32->uid;
-				n->gid = n32->gid;
-				n->file_mode = n32->file_mode;
-				n->dir_mode = n32->dir_mode;
-				memcpy(raw_data, n, sizeof(*n)); 
-			}
-			break;
-		default:
-			/* do not touch unknown structures */
-			break;
-	}
-	return raw_data;
-}
-
-struct smb_mount_data32 {
-        int version;
-        compat_uid_t mounted_uid;
-        compat_uid_t uid;
-        compat_gid_t gid;
-        compat_mode_t file_mode;
-        compat_mode_t dir_mode;
-};
-
-static void *do_smb_super_data_conv(void *raw_data)
-{
-	struct smb_mount_data news, *s = &news;
-	struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data;
-
-	if (s32->version != SMB_MOUNT_OLDVERSION)
-		goto out;
-	s->version = s32->version;
-	s->mounted_uid = low2highuid(s32->mounted_uid);
-	s->uid = low2highuid(s32->uid);
-	s->gid = low2highgid(s32->gid);
-	s->file_mode = s32->file_mode;
-	s->dir_mode = s32->dir_mode;
-	memcpy(raw_data, s, sizeof(struct smb_mount_data)); 
-out:
-	return raw_data;
-}
-
-static int copy_mount_stuff_to_kernel(const void *user, unsigned long *kernel)
-{
-	int i;
-	unsigned long page;
-	struct vm_area_struct *vma;
-
-	*kernel = 0;
-	if(!user)
-		return 0;
-	vma = find_vma(current->mm, (unsigned long)user);
-	if(!vma || (unsigned long)user < vma->vm_start)
-		return -EFAULT;
-	if(!(vma->vm_flags & VM_READ))
-		return -EFAULT;
-	i = vma->vm_end - (unsigned long) user;
-	if(PAGE_SIZE <= (unsigned long) i)
-		i = PAGE_SIZE - 1;
-	if(!(page = __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
-	if(copy_from_user((void *) page, user, i)) {
-		free_page(page);
-		return -EFAULT;
-	}
-	*kernel = page;
-	return 0;
-}
-
-#define SMBFS_NAME	"smbfs"
-#define NCPFS_NAME	"ncpfs"
-
-asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
-{
-	unsigned long type_page = 0;
-	unsigned long data_page = 0;
-	unsigned long dev_page = 0;
-	unsigned long dir_page = 0;
-	int err, is_smb, is_ncp;
-
-	is_smb = is_ncp = 0;
-
-	err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
-	if (err)
-		goto out;
-
-	if (!type_page) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	is_smb = !strcmp((char *)type_page, SMBFS_NAME);
-	is_ncp = !strcmp((char *)type_page, NCPFS_NAME);
-
-	err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
-	if (err)
-		goto type_out;
-
-	err = copy_mount_stuff_to_kernel(dev_name, &dev_page);
-	if (err)
-		goto data_out;
-
-	err = copy_mount_stuff_to_kernel(dir_name, &dir_page);
-	if (err)
-		goto dev_out;
-
-	if (!is_smb && !is_ncp) {
-		lock_kernel();
-		err = do_mount((char*)dev_page, (char*)dir_page,
-				(char*)type_page, new_flags, (char*)data_page);
-		unlock_kernel();
-	} else {
-		if (is_ncp)
-			do_ncp_super_data_conv((void *)data_page);
-		else
-			do_smb_super_data_conv((void *)data_page);
-
-		lock_kernel();
-		err = do_mount((char*)dev_page, (char*)dir_page,
-				(char*)type_page, new_flags, (char*)data_page);
-		unlock_kernel();
-	}
-	free_page(dir_page);
-
-dev_out:
-	free_page(dev_page);
-
-data_out:
-	free_page(data_page);
-
-type_out:
-	free_page(type_page);
-
-out:
-	return err;
-}
-
 struct sysinfo32 {
         s32 uptime;
         u32 loads[3];
@@ -1786,9 +1576,12 @@
 
         if (act) {
 		compat_old_sigset_t mask;
+		u32 u_handler, u_restorer;
 		
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
-		ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+		ret = get_user(u_handler, &act->sa_handler);
+		new_ka.sa.sa_handler = (void *) (long) u_handler;
+		ret |= __get_user(u_restorer, &act->sa_restorer);
+		new_ka.sa.sa_restorer = (void *) (long) u_restorer;
 		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
 		ret |= __get_user(mask, &act->sa_mask);
 		if (ret)
@@ -1827,8 +1620,11 @@
 	set_thread_flag(TIF_NEWSIGNALS);
 
         if (act) {
+		u32 u_handler, u_restorer;
+
 		new_ka.ka_restorer = restorer;
-		ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+		ret = get_user(u_handler, &act->sa_handler);
+		new_ka.sa.sa_handler = (void *) (long) u_handler;
 		ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t));
 		switch (_NSIG_WORDS) {
 		case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
@@ -1837,7 +1633,8 @@
 		case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
 		}
 		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-		ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+		ret |= __get_user(u_restorer, &act->sa_restorer);
+		new_ka.sa.sa_restorer = (void *) (long) u_restorer;
                 if (ret)
                 	return -EFAULT;
 	}
diff -Nru a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
--- a/arch/sparc64/kernel/sys_sunos32.c	Sat Apr  3 19:38:44 2004
+++ b/arch/sparc64/kernel/sys_sunos32.c	Sat Apr  3 19:38:44 2004
@@ -302,7 +302,7 @@
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *) dirent + reclen;
 	buf->curr = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -382,7 +382,7 @@
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void *) dirent + reclen;
 	buf->curr = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -1276,10 +1276,12 @@
 
 	if (act) {
 		compat_old_sigset_t mask;
+		u32 u_handler;
 
-		if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) ||
+		if (get_user(u_handler, &((struct old_sigaction32 *)A(act))->sa_handler) ||
 		    __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags))
 			return -EFAULT;
+		new_ka.sa.sa_handler = (void *) (long) u_handler;
 		__get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask);
 		new_ka.sa.sa_restorer = NULL;
 		new_ka.ka_restorer = NULL;
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc64/kernel/systbls.S	Sat Apr  3 19:38:43 2004
@@ -52,7 +52,7 @@
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_getdents64
 	.word compat_sys_fcntl64, sys_ni_syscall, compat_sys_statfs, compat_sys_fstatfs, sys_oldumount
 /*160*/	.word compat_sys_sched_setaffinity, compat_sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
-	.word sys_quotactl, sys_set_tid_address, sys32_mount, sys_ustat, sys_setxattr
+	.word sys_quotactl, sys_set_tid_address, compat_sys_mount, sys_ustat, sys_setxattr
 /*170*/	.word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys32_getdents
 	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
diff -Nru a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c
--- a/arch/sparc64/mm/hugetlbpage.c	Sat Apr  3 19:38:45 2004
+++ b/arch/sparc64/mm/hugetlbpage.c	Sat Apr  3 19:38:45 2004
@@ -497,6 +497,13 @@
 	return (size + ~HPAGE_MASK)/HPAGE_SIZE <= htlbpagemem;
 }
 
+/* Return the number pages of memory we physically have, in PAGE_SIZE units. */
+unsigned long hugetlb_total_pages(void)
+{
+	return htlbzone_pages * (HPAGE_SIZE / PAGE_SIZE);
+}
+EXPORT_SYMBOL(hugetlb_total_pages);
+
 /*
  * We cannot handle pagefaults against hugetlb pages at all.  They cause
  * handle_mm_fault() to try to instantiate regular-sized pages in the
diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c	Sat Apr  3 19:38:42 2004
+++ b/arch/sparc64/mm/init.c	Sat Apr  3 19:38:42 2004
@@ -104,7 +104,7 @@
                                 if (page2)
                                         page2->lru.next = page->lru.next;
                                 else
-                                        (struct page *)pgd_quicklist = page->lru.next;
+                                        pgd_quicklist = (void *) page->lru.next;
                                 pgd_cache_size -= 2;
                                 __free_page(page);
                                 if (page2)
diff -Nru a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
--- a/arch/sparc64/solaris/timod.c	Sat Apr  3 19:38:43 2004
+++ b/arch/sparc64/solaris/timod.c	Sat Apr  3 19:38:43 2004
@@ -296,7 +296,7 @@
 		SOLD("calling GETSOCKOPT");
 		set_fs(KERNEL_DS);
 		error = sys_socketcall(SYS_GETSOCKOPT, args);
-		set_fs(old_fs);;
+		set_fs(old_fs);
 		if (error) {
 			failed = TBADOPT;
 			break;
diff -Nru a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c
--- a/arch/v850/kernel/rte_mb_a_pci.c	Sat Apr  3 19:38:42 2004
+++ b/arch/v850/kernel/rte_mb_a_pci.c	Sat Apr  3 19:38:42 2004
@@ -687,10 +687,11 @@
    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 @@
 	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 @@
 }
 
 /* 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_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 -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
--- a/arch/x86_64/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/arch/x86_64/Kconfig	Sat Apr  3 19:38:55 2004
@@ -160,9 +160,10 @@
 	  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 @@
 	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 @@
 	depends on IA32_EMULATION
 	default y
 
+config SYSVIPC_COMPAT
+	bool
+	depends on COMPAT && SYSVIPC
+	default y
 
 config UID16
 	bool
diff -Nru a/arch/x86_64/Makefile b/arch/x86_64/Makefile
--- a/arch/x86_64/Makefile	Sat Apr  3 19:38:55 2004
+++ b/arch/x86_64/Makefile	Sat Apr  3 19:38:55 2004
@@ -63,7 +63,7 @@
 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 -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig
--- a/arch/x86_64/defconfig	Sat Apr  3 19:38:45 2004
+++ b/arch/x86_64/defconfig	Sat Apr  3 19:38:45 2004
@@ -48,6 +48,7 @@
 CONFIG_OBSOLETE_MODPARM=y
 # CONFIG_MODVERSIONS is not set
 # CONFIG_KMOD is not set
+CONFIG_STOP_MACHINE=y
 
 #
 # Processor type and features
@@ -106,7 +107,6 @@
 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,6 +119,7 @@
 #
 CONFIG_PCI=y
 CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
 # CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
 
@@ -128,8 +129,9 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 CONFIG_IA32_EMULATION=y
-# CONFIG_IA32_AOUT is not set
+CONFIG_IA32_AOUT=y
 CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
 CONFIG_UID16=y
 
 #
@@ -139,6 +141,7 @@
 #
 # Generic Driver Options
 #
+# CONFIG_DEBUG_DRIVER is not set
 
 #
 # Memory Technology Devices (MTD)
@@ -165,11 +168,11 @@
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_CARMEL 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
 
 #
 # ATA/ATAPI/MFM/RLL support
@@ -210,6 +213,7 @@
 # CONFIG_BLK_DEV_AEC62XX is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 CONFIG_BLK_DEV_AMD74XX=y
+# CONFIG_BLK_DEV_ATIIXP is not set
 # CONFIG_BLK_DEV_CMD64X is not set
 # CONFIG_BLK_DEV_TRIFLEX is not set
 # CONFIG_BLK_DEV_CY82C693 is not set
@@ -231,7 +235,6 @@
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_IDEDMA_IVB is not set
 CONFIG_IDEDMA_AUTO=y
-# CONFIG_DMA_NONPCI is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -258,9 +261,15 @@
 # CONFIG_SCSI_LOGGING is not set
 
 #
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
 # 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,12 @@
 # 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_SATA_VITESSE is not set
 # CONFIG_SCSI_BUSLOGIC is not set
 # CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DMX3191D is not set
@@ -302,7 +316,6 @@
 # Fusion MPT device support
 #
 CONFIG_FUSION=y
-CONFIG_FUSION_BOOT=y
 CONFIG_FUSION_MAX_SGE=40
 # CONFIG_FUSION_ISENSE is not set
 # CONFIG_FUSION_CTL is not set
@@ -317,10 +330,6 @@
 #
 
 #
-# Macintosh device drivers
-#
-
-#
 # Networking support
 #
 CONFIG_NET=y
@@ -467,6 +476,7 @@
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
 # CONFIG_SHAPER is not set
+CONFIG_NETCONSOLE=y
 
 #
 # Wan interfaces
@@ -487,6 +497,10 @@
 # Bluetooth support
 #
 # CONFIG_BT is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
 
 #
 # ISDN subsystem
@@ -532,11 +546,13 @@
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
@@ -566,11 +582,6 @@
 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
 
 #
@@ -607,6 +618,11 @@
 # CONFIG_I2C is not set
 
 #
+# Misc devices
+#
+# CONFIG_IBM_ASM is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -759,11 +775,12 @@
 CONFIG_LOCKD_V4=y
 CONFIG_EXPORTFS=y
 CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
 # 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
 
 #
diff -Nru a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile
--- a/arch/x86_64/ia32/Makefile	Sat Apr  3 19:38:42 2004
+++ b/arch/x86_64/ia32/Makefile	Sat Apr  3 19:38:42 2004
@@ -11,18 +11,22 @@
 
 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 -Nru a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
--- a/arch/x86_64/ia32/ia32_binfmt.c	Sat Apr  3 19:38:41 2004
+++ b/arch/x86_64/ia32/ia32_binfmt.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 
 #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 @@
 		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 -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c
--- a/arch/x86_64/ia32/ia32_ioctl.c	Sat Apr  3 19:38:43 2004
+++ b/arch/x86_64/ia32/ia32_ioctl.c	Sat Apr  3 19:38:43 2004
@@ -27,7 +27,7 @@
 	struct file *file = fget(fd);
 	struct tty_struct *real_tty;
 
-	if (!fd)
+	if (!file)
 		return -EBADF;
 	if (file->f_op->ioctl != tty_ioctl)
 		return -EINVAL; 
diff -Nru a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
--- a/arch/x86_64/ia32/ia32_signal.c	Sat Apr  3 19:38:56 2004
+++ b/arch/x86_64/ia32/ia32_signal.c	Sat Apr  3 19:38:56 2004
@@ -273,8 +273,6 @@
 	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)
@@ -304,8 +302,6 @@
 	sigset_t set;
 	stack_t st;
 	unsigned int eax;
-
-	set_thread_flag(TIF_IRET);
 
 	if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
 		goto badframe;
diff -Nru a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
--- a/arch/x86_64/ia32/ia32entry.S	Sat Apr  3 19:38:43 2004
+++ b/arch/x86_64/ia32/ia32entry.S	Sat Apr  3 19:38:43 2004
@@ -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)
+	bt  $TIF_SYSCALL_TRACE,threadinfo_flags(%r10)
+	jc  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
+	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 @@
 	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 @@
 	/* 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
+	jc  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
 	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,7 +234,7 @@
 	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
@@ -148,6 +243,7 @@
 	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 
 
@@ -200,8 +296,7 @@
 	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
@@ -231,7 +326,7 @@
 	.quad sys_stat
 	.quad sys32_lseek
 	.quad sys_getpid		/* 20 */
-	.quad sys_mount	/* mount  */
+	.quad compat_sys_mount	/* mount  */
 	.quad sys_oldumount	/* old_umount  */
 	.quad sys_setuid16
 	.quad sys_getuid16
diff -Nru a/arch/x86_64/ia32/ipc32.c b/arch/x86_64/ia32/ipc32.c
--- a/arch/x86_64/ia32/ipc32.c	Sat Apr  3 19:38:43 2004
+++ b/arch/x86_64/ia32/ipc32.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	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 -Nru a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
--- a/arch/x86_64/ia32/sys_ia32.c	Sat Apr  3 19:38:43 2004
+++ b/arch/x86_64/ia32/sys_ia32.c	Sat Apr  3 19:38:43 2004
@@ -40,9 +40,6 @@
 #include <linux/slab.h>
 #include <linux/uio.h>
 #include <linux/nfs_fs.h>
-#include <linux/smb_fs.h>
-#include <linux/smb_mount.h>
-#include <linux/ncp_fs.h>
 #include <linux/quota.h>
 #include <linux/module.h>
 #include <linux/sunrpc/svc.h>
@@ -63,6 +60,7 @@
 #include <linux/vfs.h>
 #include <linux/ptrace.h>
 #include <linux/highuid.h>
+#include <linux/vmalloc.h>
 #include <asm/mman.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
@@ -512,7 +510,7 @@
 {
 	struct linux32_dirent * dirent;
 	struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
-	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
+	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2, 4);
 
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count)
@@ -526,6 +524,7 @@
 	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
+	put_user(d_type, (char *)dirent + reclen - 1); 
 	dirent = ((void *)dirent) + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
@@ -874,39 +873,6 @@
 	return sys_sysfs(option, arg1, arg2);
 }
 
-static char *badfs[] = {
-	"smbfs", "ncpfs", NULL
-}; 	
-
-static int checktype(char *user_type) 
-{ 
-	int err = 0; 
-	char **s,*kernel_type = getname(user_type); 
-	if (!kernel_type || IS_ERR(kernel_type)) 
-		return -EFAULT; 
-	for (s = badfs; *s; ++s) 
-		if (!strcmp(kernel_type, *s)) { 
-			printk(KERN_ERR "mount32: unsupported fs `%s' -- use 64bit mount\n", *s); 
-			err = -EINVAL; 
-			break;
-		} 	
-	putname(user_type); 
-	return err;
-} 
-
-asmlinkage long
-sys32_mount(char *dev_name, char *dir_name, char *type,
-	    unsigned long new_flags, u32 data)
-{
-	int err;
-	if(!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	err = checktype(type);
-	if (err)
-		return err;
-	return sys_mount(dev_name, dir_name, type, new_flags, (void *)AA(data));
-}
-
 struct sysinfo32 {
         s32 uptime;
         u32 loads[3];
@@ -1876,18 +1842,9 @@
 
 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 -Nru a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
--- a/arch/x86_64/ia32/syscall32.c	Sat Apr  3 19:38:45 2004
+++ b/arch/x86_64/ia32/syscall32.c	Sat Apr  3 19:38:45 2004
@@ -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 @@
 	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 -Nru a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/ia32/vsyscall-sigreturn.S	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/arch/x86_64/ia32/vsyscall-syscall.S b/arch/x86_64/ia32/vsyscall-syscall.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/ia32/vsyscall-syscall.S	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/arch/x86_64/ia32/vsyscall-sysenter.S b/arch/x86_64/ia32/vsyscall-sysenter.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/ia32/vsyscall-sysenter.S	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/arch/x86_64/ia32/vsyscall.S b/arch/x86_64/ia32/vsyscall.S
--- a/arch/x86_64/ia32/vsyscall.S	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
--- a/arch/x86_64/kernel/Makefile	Sat Apr  3 19:38:54 2004
+++ b/arch/x86_64/kernel/Makefile	Sat Apr  3 19:38:54 2004
@@ -8,10 +8,10 @@
 		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_ACPI_BOOT)		+= acpi/
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
diff -Nru a/arch/x86_64/kernel/acpi/Makefile b/arch/x86_64/kernel/acpi/Makefile
--- a/arch/x86_64/kernel/acpi/Makefile	Sat Apr  3 19:38:43 2004
+++ b/arch/x86_64/kernel/acpi/Makefile	Sat Apr  3 19:38:43 2004
@@ -1,3 +1,3 @@
 obj-$(CONFIG_ACPI_BOOT)		:= boot.o
+boot-$(CONFIG_ACPI_BOOT)	:= ../../../i386/kernel/acpi/boot.o
 obj-$(CONFIG_ACPI_SLEEP)	+= sleep.o wakeup.o
-
diff -Nru a/arch/x86_64/kernel/acpi/boot.c b/arch/x86_64/kernel/acpi/boot.c
--- a/arch/x86_64/kernel/acpi/boot.c	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,557 +0,0 @@
-/*
- *  acpi.c - Architecture-Specific Low-Level ACPI Support
- *
- *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
- *  Copyright (C) 2001 Jun Nakajima <jun.nakajima@intel.com>
- *  Copyright (C) 2001 Patrick Mochel <mochel@osdl.org>
- *  Copyright (C) 2002 Andi Kleen, SuSE Labs (x86-64 port)
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  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/config.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/bootmem.h>
-#include <linux/irq.h>
-#include <linux/acpi.h>
-#include <asm/mpspec.h>
-#include <asm/io.h>
-#include <asm/apic.h>
-#include <asm/apicdef.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
-#include <asm/io_apic.h>
-#include <asm/proto.h>
-#include <asm/tlbflush.h>
-
-#define PREFIX			"ACPI: "
-
-int acpi_noirq __initdata;	/* skip ACPI IRQ initialization */
-int acpi_ht __initdata = 1;	/* enable HT */
-
-int acpi_lapic;
-int acpi_ioapic;
-int acpi_strict;
-
-/* --------------------------------------------------------------------------
-                              Boot-time Configuration
-   -------------------------------------------------------------------------- */
-
-#ifdef CONFIG_ACPI_BOOT
-
-enum acpi_irq_model_id		acpi_irq_model;
-
-/* rely on all ACPI tables being in the direct mapping */
-char *
-__acpi_map_table (
-	unsigned long	phys_addr,
-	unsigned long	size)
-{
-	if (!phys_addr || !size)
-		return NULL;
-
-	if (phys_addr < (end_pfn_map << PAGE_SHIFT)) 
-		return __va(phys_addr); 
-
-	return NULL; 
-} 	      
-
-#ifdef CONFIG_X86_LOCAL_APIC
-
-static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
-
-
-static int __init
-acpi_parse_madt (
-	unsigned long		phys_addr,
-	unsigned long		size)
-{
-	struct acpi_table_madt	*madt = NULL;
-
-	if (!phys_addr || !size)
-		return -EINVAL;
-
-	madt = (struct acpi_table_madt *) __acpi_map_table(phys_addr, size);
-	if (!madt) {
-		printk(KERN_WARNING PREFIX "Unable to map MADT\n");
-		return -ENODEV;
-	}
-
-	if (madt->lapic_address)
-		acpi_lapic_addr = (u64) madt->lapic_address;
-
-	printk(KERN_INFO PREFIX "Local APIC address 0x%016x\n",
-		madt->lapic_address);
-
-	return 0;
-}
-
-
-static int __init
-acpi_parse_lapic (
-	acpi_table_entry_header *header)
-{
-	struct acpi_table_lapic	*processor = NULL;
-
-	processor = (struct acpi_table_lapic*) header;
-	if (!processor)
-		return -EINVAL;
-
-	acpi_table_print_madt_entry(header);
-
-	/* no utility in registering a disabled processor */
-	if (processor->flags.enabled == 0)
-		return 0;
-
-
-	mp_register_lapic (
-		processor->id,					   /* APIC ID */
-		processor->flags.enabled);			  /* Enabled? */
-
-	return 0;
-}
-
-
-static int __init
-acpi_parse_lapic_addr_ovr (
-	acpi_table_entry_header *header)
-{
-	struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL;
-
-	lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr*) header;
-	if (!lapic_addr_ovr)
-		return -EINVAL;
-
-	acpi_lapic_addr = lapic_addr_ovr->address;
-
-	return 0;
-}
-
-
-static int __init
-acpi_parse_lapic_nmi (
-	acpi_table_entry_header *header)
-{
-	struct acpi_table_lapic_nmi *lapic_nmi = NULL;
-
-	lapic_nmi = (struct acpi_table_lapic_nmi*) header;
-	if (!lapic_nmi)
-		return -EINVAL;
-
-	acpi_table_print_madt_entry(header);
-
-	if (lapic_nmi->lint != 1)
-		printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n");
-
-	return 0;
-}
-
-#endif /*CONFIG_X86_LOCAL_APIC*/
-
-#ifdef CONFIG_X86_IO_APIC
-
-static int __init
-acpi_parse_ioapic (
-	acpi_table_entry_header *header)
-{
-	struct acpi_table_ioapic *ioapic = NULL;
-
-	ioapic = (struct acpi_table_ioapic*) header;
-	if (!ioapic)
-		return -EINVAL;
- 
-	acpi_table_print_madt_entry(header);
-
-	mp_register_ioapic (
-		ioapic->id,
-		ioapic->address,
-		ioapic->global_irq_base);
- 
-	return 0;
-}
-
-
-static int __init
-acpi_parse_int_src_ovr (
-	acpi_table_entry_header *header)
-{
-	struct acpi_table_int_src_ovr *intsrc = NULL;
-
-	intsrc = (struct acpi_table_int_src_ovr*) header;
-	if (!intsrc)
-		return -EINVAL;
-
-	acpi_table_print_madt_entry(header);
-
-	mp_override_legacy_irq (
-		intsrc->bus_irq,
-		intsrc->flags.polarity,
-		intsrc->flags.trigger,
-		intsrc->global_irq);
-
-	return 0;
-}
-
-
-static int __init
-acpi_parse_nmi_src (
-	acpi_table_entry_header *header)
-{
-	struct acpi_table_nmi_src *nmi_src = NULL;
-
-	nmi_src = (struct acpi_table_nmi_src*) header;
-	if (!nmi_src)
-		return -EINVAL;
-
-	acpi_table_print_madt_entry(header);
-
-	/* TBD: Support nimsrc entries? */
-
-	return 0;
-}
-
-#endif /*CONFIG_X86_IO_APIC*/
-
-#ifdef CONFIG_HPET_TIMER
-static int __init
-acpi_parse_hpet (
-	unsigned long		phys_addr,
-	unsigned long		size)
-{
-	struct acpi_table_hpet *hpet_tbl;
-
-	hpet_tbl = __va(phys_addr);
-
-	if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) {
-		printk(KERN_WARNING "acpi: HPET timers must be located in memory.\n");
-		return -1;
-	}
-
-	vxtime.hpet_address = hpet_tbl->addr.addrl |
-		((long) hpet_tbl->addr.addrh << 32);
-
-	printk(KERN_INFO "acpi: HPET id: %#x base: %#lx\n",
-	       hpet_tbl->id, vxtime.hpet_address);
-
-	return 0;
-} 
-#endif
-
-#ifdef CONFIG_ACPI_BUS
-/*
- * "acpi_pic_sci=level" (current default)
- * programs the PIC-mode SCI to Level Trigger.
- * (NO-OP if the BIOS set Level Trigger already)
- *
- * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
- * it may require Edge Trigger -- use "acpi_pic_sci=edge"
- * (NO-OP if the BIOS set Edge Trigger already)
- *
- * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers
- * for the 8259 PIC.  bit[n] = 1 means irq[n] is Level, otherwise Edge.
- * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0)
- * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0)
- */
-
-static int __initdata	acpi_pic_sci_trigger;	/* 0: level, 1: edge */
-
-void __init
-acpi_pic_sci_set_trigger(unsigned int irq)
-{
-	unsigned char mask = 1 << (irq & 7);
-	unsigned int port = 0x4d0 + (irq >> 3);
-	unsigned char val = inb(port);
-
-	
-	printk(PREFIX "IRQ%d SCI:", irq);
-	if (!(val & mask)) {
-		printk(" Edge");
-
-		if (!acpi_pic_sci_trigger) {
-			printk(" set to Level");
-			outb(val | mask, port);
-		}
-	} else {
-		printk(" Level");
-
-		if (acpi_pic_sci_trigger) {
-			printk(" set to Edge");
-			outb(val | mask, port);
-		}
-	}
-	printk(" Trigger.\n");
-}
-
-int __init
-acpi_pic_sci_setup(char *str)
-{
-	while (str && *str) {
-		if (strncmp(str, "level", 5) == 0)
-			acpi_pic_sci_trigger = 0;	/* force level trigger */
-		if (strncmp(str, "edge", 4) == 0)
-			acpi_pic_sci_trigger = 1;	/* force edge trigger */
-		str = strchr(str, ',');
-		if (str)
-			str += strspn(str, ", \t");
-	}
-	return 1;
-}
-
-__setup("acpi_pic_sci=", acpi_pic_sci_setup);
-
-#endif /* CONFIG_ACPI_BUS */
-
-static unsigned long __init
-acpi_scan_rsdp (
-	unsigned long		start,
-	unsigned long		length)
-{
-	unsigned long		offset = 0;
-	unsigned long		sig_len = sizeof("RSD PTR ") - 1;
-
-	/*
-	 * Scan all 16-byte boundaries of the physical memory region for the
-	 * RSDP signature.
-	 */
-	for (offset = 0; offset < length; offset += 16) {
-		if (strncmp((char *) (start + offset), "RSD PTR ", sig_len))
-			continue;
-		return (start + offset);
-	}
-
-	return 0;
-}
-
-
-unsigned long __init
-acpi_find_rsdp (void)
-{
-	unsigned long		rsdp_phys = 0;
-
-	/*
-	 * Scan memory looking for the RSDP signature. First search EBDA (low
-	 * memory) paragraphs and then search upper memory (E0000-FFFFF).
-	 */
-	rsdp_phys = acpi_scan_rsdp (0, 0x400);
-	if (!rsdp_phys)
-		rsdp_phys = acpi_scan_rsdp (0xE0000, 0xFFFFF);
-
-	return rsdp_phys;
-}
-
-/*
- * acpi_boot_init()
- *  called from setup_arch(), always.
- *     1. maps ACPI tables for later use
- *     2. enumerates lapics
- *     3. enumerates io-apics
- *
- * side effects:
- *     acpi_lapic = 1 if LAPIC found
- *     acpi_ioapic = 1 if IOAPIC found
- *     if (acpi_lapic && acpi_ioapic) smp_found_config = 1;
- *     if acpi_blacklisted() acpi_disabled = 1;
- *     acpi_irq_model=...
- *     ...
- *
- * return value: (currently ignored)
- *     0: success
- *     !0: failure
- */
-
-int __init
-acpi_boot_init (void)
-{
-	int			result = 0;
-
-	if (acpi_disabled && !acpi_ht)
-		return 1;
-
-	/*
-	 * The default interrupt routing model is PIC (8259).  This gets
-	 * overriden if IOAPICs are enumerated (below).
-	 */
-	acpi_irq_model = ACPI_IRQ_MODEL_PIC;
-
-	/* 
-	 * Initialize the ACPI boot-time table parser.
-	 */
-	result = acpi_table_init();
-	if (result) {
-		acpi_disabled = 1;
-		return result;
-	}
-
-	result = acpi_blacklisted();
-	if (result) {
-		printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n");
-		acpi_disabled = 1;
-		return result;
-	}
-
-	if (disable_apic) { 
-		printk(KERN_INFO PREFIX "Skipping MADT probe because local APIC is disabled\n");
-		return 0;
-	}
-
-#ifdef CONFIG_X86_LOCAL_APIC
-
-	/* 
-	 * MADT
-	 * ----
-	 * Parse the Multiple APIC Description Table (MADT), if exists.
-	 * Note that this table provides platform SMP configuration 
-	 * information -- the successor to MPS tables.
-	 */
-
-	result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
-	if (!result) {
-		printk(KERN_WARNING PREFIX "MADT not present\n");
-		return 0;
-	}
-	else if (result < 0) {
-		printk(KERN_ERR PREFIX "Error parsing MADT\n");
-		return result;
-	}
-	else if (result > 1) 
-		printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n");
-
-	/* 
-	 * Local APIC
-	 * ----------
-	 * Note that the LAPIC address is obtained from the MADT (32-bit value)
-	 * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
-	 */
-
-	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0);
-	if (result < 0) {
-		printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");
-		return result;
-	}
-
-	mp_register_lapic_address(acpi_lapic_addr);
-
-	result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
-				       MAX_APICS);
-	if (!result) { 
-		printk(KERN_ERR PREFIX "No LAPIC entries present\n");
-		/* TBD: Cleanup to allow fallback to MPS */
-		return -ENODEV;
-	}
-	else if (result < 0) {
-		printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n");
-		/* TBD: Cleanup to allow fallback to MPS */
-		return result;
-	}
-
-	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0);
-	if (result < 0) {
-		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
-		/* TBD: Cleanup to allow fallback to MPS */
-		return result;
-	}
-
-	acpi_lapic = 1;
-
-#endif /*CONFIG_X86_LOCAL_APIC*/
-
-#ifdef CONFIG_X86_IO_APIC
-
-	/* 
-	 * I/O APIC 
-	 * --------
-	 */
-
-       /*
-        * ACPI interpreter is required to complete interrupt setup,
-        * so if it is off, don't enumerate the io-apics with ACPI.
-        * If MPS is present, it will handle them,
-        * otherwise the system will stay in PIC mode
-        */
-        if (acpi_disabled || acpi_noirq) {
-               return 1;
-	}
-
-	/*
-	 * if "noapic" boot option, don't look for IO-APICs
-	 */
-	if (skip_ioapic_setup) {
-		printk(KERN_INFO PREFIX "Skipping IOAPIC probe "
-		       "due to 'noapic' option.\n");
-		return 1;
-	}
-
-	result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS);
-	if (!result) {
-		printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
-		return -ENODEV;
-	}
-	else if (result < 0) {
-		printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n");
-		return result;
-	}
-
-	/* Build a default routing table for legacy (ISA) interrupts. */
-	mp_config_acpi_legacy_irqs();
-
-	result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS);
-	if (result < 0) {
-		printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");
-		/* TBD: Cleanup to allow fallback to MPS */
-		return result;
-	}
-
-	result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src,
-				       NR_IRQ_VECTORS);
-	if (result < 0) {
-		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
-		/* TBD: Cleanup to allow fallback to MPS */
-		return result;
-	}
-
-	acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
-
-	acpi_irq_balance_set(NULL);
-
-	acpi_ioapic = 1;
-
-#endif /*CONFIG_X86_IO_APIC*/
-
-#ifdef CONFIG_X86_LOCAL_APIC
-	if (acpi_lapic && acpi_ioapic)
-		smp_found_config = 1;
-#endif
-
-#ifdef CONFIG_HPET_TIMER
-	result = acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
-	if (result < 0) 
-		printk("ACPI: no HPET table found (%d).\n", result); 
-#endif
-
-	return 0;
-}
-
-#endif /*CONFIG_ACPI_BOOT*/
-
diff -Nru a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
--- a/arch/x86_64/kernel/entry.S	Sat Apr  3 19:38:42 2004
+++ b/arch/x86_64/kernel/entry.S	Sat Apr  3 19:38:42 2004
@@ -226,7 +226,7 @@
 	/* 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 */
@@ -307,7 +307,7 @@
 	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
@@ -402,9 +402,9 @@
 /* 0(%rsp): interrupt number */ 
 	.macro interrupt func
 	CFI_STARTPROC	simple
-	CFI_DEF_CFA	rsp,(SS-ORIG_RAX)
-	CFI_OFFSET	rsp,(RSP-SS)
-	CFI_OFFSET	rip,(RIP-SS)
+	CFI_DEF_CFA	rsp,(SS-RDI)
+	CFI_REL_OFFSET	rsp,(RSP-ORIG_RAX)
+	CFI_REL_OFFSET	rip,(RIP-ORIG_RAX)
 	cld
 #ifdef CONFIG_DEBUG_INFO
 	SAVE_ALL	
@@ -489,7 +489,7 @@
 	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 +572,24 @@
 	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 +643,7 @@
 	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 +795,56 @@
 	zeroentry do_simd_coprocessor_error	
 
 ENTRY(device_not_available)
+	zeroentry math_state_restore
+
+	/* runs on exception stack */
+ENTRY(debug)
 	CFI_STARTPROC
-	pushq $-1	#error code
-	SAVE_ALL
-	movl  $1,%ebx
+	pushq $0
+	CFI_ADJUST_CFA_OFFSET 8		
+	paranoidentry do_debug
+	/* switch back to process stack to restore the state ptrace touched */
+	movq %rax,%rsp	
 	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
+	jnz   paranoid_userspace	
+	jmp paranoid_exit
 	CFI_ENDPROC
 
-ENTRY(debug)
-	zeroentry do_debug
-
+	/* 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 %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 +865,15 @@
 ENTRY(reserved)
 	zeroentry do_reserved
 
+	/* runs on exception stack */
 ENTRY(double_fault)
-	errorentry do_double_fault	
+	CFI_STARTPROC
+	paranoidentry do_double_fault
+	movq %rax,%rsp
+	testl $3,CS(%rsp)
+	jnz paranoid_userspace		
+	jmp paranoid_exit
+	CFI_ENDPROC
 
 ENTRY(invalid_TSS)
 	errorentry do_invalid_TSS
@@ -847,8 +881,15 @@
 ENTRY(segment_not_present)
 	errorentry do_segment_not_present
 
+	/* runs on exception stack */
 ENTRY(stack_segment)
-	errorentry do_stack_segment
+	CFI_STARTPROC
+	paranoidentry do_stack_segment
+	movq %rax,%rsp
+	testl $3,CS(%rsp)
+	jnz paranoid_userspace
+	jmp paranoid_exit
+	CFI_ENDPROC
 
 ENTRY(general_protection)
 	errorentry do_general_protection
@@ -862,8 +903,14 @@
 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 -Nru a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
--- a/arch/x86_64/kernel/io_apic.c	Sat Apr  3 19:38:43 2004
+++ b/arch/x86_64/kernel/io_apic.c	Sat Apr  3 19:38:43 2004
@@ -1891,7 +1891,11 @@
 	entry.polarity = active_high_low;
 	entry.mask = 1;					 /* Disabled (masked) */
 
-	add_pin_to_irq(irq, ioapic, pin);
+	/*
+	 * IRQs < 16 are already in the irq_2_pin[] map
+	 */
+	if (irq >= 16)
+		add_pin_to_irq(irq, ioapic, pin);
 
 	entry.vector = assign_irq_vector(irq);
 
diff -Nru a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c
--- a/arch/x86_64/kernel/ioport.c	Sat Apr  3 19:38:42 2004
+++ b/arch/x86_64/kernel/ioport.c	Sat Apr  3 19:38:42 2004
@@ -95,7 +95,5 @@
 			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 -Nru a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
--- a/arch/x86_64/kernel/mce.c	Sat Apr  3 19:38:42 2004
+++ b/arch/x86_64/kernel/mce.c	Sat Apr  3 19:38:42 2004
@@ -22,12 +22,13 @@
 #include <asm/uaccess.h>
 
 #define MISC_MCELOG_MINOR 227
+#define NR_BANKS 5
 
 static int mce_disabled __initdata;
 /* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic */ 
 static int tolerant = 2;
 static int banks;
-static unsigned long disabled_banks;
+static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
 
 /*
  * Lockless MCE logging infrastructure.
@@ -144,7 +145,7 @@
 	mb();
 
 	for (i = 0; i < banks; i++) {
-		if (test_bit(i, &disabled_banks))
+		if (!bank[i])
 			continue;
 
 		rdmsrl(MSR_IA32_MC0_STATUS + i*4, m.status);
@@ -179,7 +180,7 @@
 		   confused it's normally not necessary to panic, unless you are 
 		   paranoid (tolerant == 0) */ 
 		if (!user_space && (panic_on_oops || tolerant < 2))
-			mce_panic("Uncorrected machine check in kernel", &m, mcestart);
+			mce_panic("Uncorrected machine check", &m, mcestart);
 
 		/* do_exit takes an awful lot of locks and has as slight risk 
 		   of deadlocking. If you don't want that don't set tolerant >= 2 */
@@ -238,17 +239,31 @@
 		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
 
 	banks = cap & 0xff;
+	if (banks > NR_BANKS) { 
+		printk(KERN_INFO "MCE: warning: using only %d banks\n", banks);
+		banks = NR_BANKS; 
+	}
 
 	mce_clear_all(); 
 	for (i = 0; i < banks; i++) {
-		u64 val = test_bit(i, &disabled_banks) ? 0 : ~0UL;
-		wrmsrl(MSR_IA32_MC0_CTL+4*i, val);
+		wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
 		wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
 	}	
 
 	set_in_cr4(X86_CR4_MCE);
 }
 
+/* Add per CPU specific workarounds here */
+static void __init mce_cpu_quirks(struct cpuinfo_x86 *c) 
+{ 
+	/* This should be disabled by the BIOS, but isn't always */
+	if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 15) {
+		/* disable GART TBL walk error reporting, which trips off 
+		   incorrectly with the IOMMU & 3ware & Cerberus. */
+		clear_bit(10, &bank[4]);
+	}
+}			
+
 /* 
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off. 
@@ -257,6 +272,8 @@
 {
 	static unsigned long mce_cpus __initdata = 0;
 
+	mce_cpu_quirks(c); 
+
 	if (test_and_set_bit(smp_processor_id(), &mce_cpus) || !mce_available(c))
 		return;
 
@@ -343,23 +360,9 @@
 	} 
 }
 
-#if 0 /* for testing */
-static ssize_t mce_write(struct file *f, const char __user *buf, size_t sz, loff_t *off)
-{
-	struct mce m;
-	if (sz != sizeof(struct mce))
-		return -EINVAL;
-	copy_from_user(&m, buf, sizeof(struct mce));
-	m.finished = 0;
-	mce_log(&m);
-	return sizeof(struct mce);
-}
-#endif
-
 static struct file_operations mce_chrdev_ops = {
 	.read = mce_read,
 	.ioctl = mce_ioctl,
-	//.write = mce_write
 };
 
 static struct miscdevice mce_log_device = {
@@ -425,23 +428,27 @@
 };
 
 /* Why are there no generic functions for this? */
-#define ACCESSOR(name, start) \
+#define ACCESSOR(name, var, start) \
 	static ssize_t show_ ## name(struct sys_device *s, char *buf) { 	   	   \
-		return sprintf(buf, "%lu\n", (unsigned long)name);		   \
+		return sprintf(buf, "%lu\n", (unsigned long)var);		   \
 	} 									   \
 	static ssize_t set_ ## name(struct sys_device *s,const char *buf,size_t siz) { \
 		char *end; 							   \
 		unsigned long new = simple_strtoul(buf, &end, 0); 		   \
 		if (end == buf) return -EINVAL;					   \
-		name = new;							   \
+		var = new;							   \
 		start; 								   \
 		return end-buf;		     					   \
 	}									   \
 	static SYSDEV_ATTR(name, 0644, show_ ## name, set_ ## name);
 
-ACCESSOR(disabled_banks,mce_restart())
-ACCESSOR(tolerant,)
-ACCESSOR(check_interval,mce_restart())
+ACCESSOR(bank0ctl,bank[0],mce_restart())
+ACCESSOR(bank1ctl,bank[1],mce_restart())
+ACCESSOR(bank2ctl,bank[2],mce_restart())
+ACCESSOR(bank3ctl,bank[3],mce_restart())
+ACCESSOR(bank4ctl,bank[4],mce_restart())
+ACCESSOR(tolerant,tolerant,)
+ACCESSOR(check_interval,check_interval,mce_restart())
 
 static __init int mce_init_device(void)
 {
@@ -453,7 +460,11 @@
 		err = sysdev_register(&device_mce);
 	if (!err) { 
 		/* could create per CPU objects, but is not worth it. */
-		sysdev_create_file(&device_mce, &attr_disabled_banks); 
+		sysdev_create_file(&device_mce, &attr_bank0ctl); 
+		sysdev_create_file(&device_mce, &attr_bank1ctl); 
+		sysdev_create_file(&device_mce, &attr_bank2ctl); 
+		sysdev_create_file(&device_mce, &attr_bank3ctl); 
+		sysdev_create_file(&device_mce, &attr_bank4ctl); 
 		sysdev_create_file(&device_mce, &attr_tolerant); 
 		sysdev_create_file(&device_mce, &attr_check_interval);
 	} 
diff -Nru a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
--- a/arch/x86_64/kernel/mpparse.c	Sat Apr  3 19:38:42 2004
+++ b/arch/x86_64/kernel/mpparse.c	Sat Apr  3 19:38:42 2004
@@ -9,7 +9,7 @@
  *		Erich Boleyn	:	MP v1.4 and additional changes.
  *		Alan Cox	:	Added EBDA scanning
  *		Ingo Molnar	:	various cleanups and rewrites
- *	Maciej W. Rozycki	:	Bits for default MP configurations
+ *		Maciej W. Rozycki:	Bits for default MP configurations
  *		Paul Diefenbaugh:	Added full ACPI support
  */
 
@@ -33,6 +33,7 @@
 
 /* Have we found an MP table */
 int smp_found_config;
+unsigned int __initdata maxcpus = NR_CPUS;
 
 int acpi_found_madt;
 
@@ -117,6 +118,17 @@
 		Dprintk("    Bootup CPU\n");
 		boot_cpu_id = m->mpc_apicid;
 	}
+	if (num_processors >= NR_CPUS) {
+		printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached."
+			" Processor ignored.\n", NR_CPUS);
+		return;
+	}
+	if (num_processors >= maxcpus) {
+		printk(KERN_WARNING "WARNING: maxcpus limit of %i reached."
+			" Processor ignored.\n", maxcpus);
+		return;
+	}
+
 	num_processors++;
 
 	if (m->mpc_apicid > MAX_APICS) {
@@ -690,25 +702,25 @@
 
 struct mp_ioapic_routing {
 	int			apic_id;
-	int			irq_start;
-	int			irq_end;
+	int			gsi_start;
+	int			gsi_end;
 	u32			pin_programmed[4];
 } mp_ioapic_routing[MAX_IO_APICS];
 
 
 static int __init mp_find_ioapic (
-	int			irq)
+	int			gsi)
 {
 	int			i = 0;
 
-	/* Find the IOAPIC that manages this IRQ. */
+	/* Find the IOAPIC that manages this GSI. */
 	for (i = 0; i < nr_ioapics; i++) {
-		if ((irq >= mp_ioapic_routing[i].irq_start)
-			&& (irq <= mp_ioapic_routing[i].irq_end))
+		if ((gsi >= mp_ioapic_routing[i].gsi_start)
+			&& (gsi <= mp_ioapic_routing[i].gsi_end))
 			return i;
 	}
 
-	printk(KERN_ERR "ERROR: Unable to locate IOAPIC for IRQ %d\n", irq);
+	printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
 
 	return -1;
 }
@@ -717,7 +729,7 @@
 void __init mp_register_ioapic (
 	u8			id, 
 	u32			address,
-	u32			irq_base)
+	u32			gsi_base)
 {
 	int			idx = 0;
 
@@ -743,19 +755,19 @@
 	mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx);
 	
 	/* 
-	 * Build basic IRQ lookup table to facilitate irq->io_apic lookups
+	 * Build basic IRQ lookup table to facilitate gsi->io_apic lookups
 	 * and to prevent reprogramming of IOAPIC pins (PCI IRQs).
 	 */
 	mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid;
-	mp_ioapic_routing[idx].irq_start = irq_base;
-	mp_ioapic_routing[idx].irq_end = irq_base + 
+	mp_ioapic_routing[idx].gsi_start = gsi_base;
+	mp_ioapic_routing[idx].gsi_end = gsi_base + 
 		io_apic_get_redir_entries(idx);
 
 	printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
-		"IRQ %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, 
+		"GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, 
 		mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr,
-		mp_ioapic_routing[idx].irq_start,
-		mp_ioapic_routing[idx].irq_end);
+		mp_ioapic_routing[idx].gsi_start,
+		mp_ioapic_routing[idx].gsi_end);
 
 	return;
 }
@@ -765,7 +777,7 @@
 	u8			bus_irq,
 	u8			polarity, 
 	u8			trigger, 
-	u32			global_irq)
+	u32			gsi)
 {
 	struct mpc_config_intsrc intsrc;
 	int			i = 0;
@@ -774,12 +786,12 @@
 	int			pin = -1;
 
 	/* 
-	 * Convert 'global_irq' to 'ioapic.pin'.
+	 * Convert 'gsi' to 'ioapic.pin'.
 	 */
-	ioapic = mp_find_ioapic(global_irq);
+	ioapic = mp_find_ioapic(gsi);
 	if (ioapic < 0)
 		return;
-	pin = global_irq - mp_ioapic_routing[ioapic].irq_start;
+	pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
 
 	/*
 	 * TBD: This check is for faulty timer entries, where the override
@@ -804,7 +816,7 @@
 
 	/* 
 	 * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it.
-	 * Otherwise create a new entry (e.g. global_irq == 2).
+	 * Otherwise create a new entry (e.g. gsi == 2).
 	 */
 	for (i = 0; i < mp_irq_entries; i++) {
 		if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) 
@@ -878,69 +890,6 @@
 
 extern FADT_DESCRIPTOR acpi_fadt;
 
-void __init mp_config_ioapic_for_sci(int irq)
-{
-	int ioapic;
-	int ioapic_pin;
-	struct acpi_table_madt *madt;
-	struct acpi_table_int_src_ovr *entry = NULL;
-	acpi_interrupt_flags flags;
-	void *madt_end;
-	acpi_status status;
-
-	/*
-	 * Ensure that if there is an interrupt source override entry
-	 * for the ACPI SCI, we leave it as is. Unfortunately this involves
-	 * walking the MADT again.
-	 */
-	status = acpi_get_firmware_table("APIC", 1, ACPI_LOGICAL_ADDRESSING,
-		(struct acpi_table_header **) &madt);
-	if (ACPI_SUCCESS(status)) {
-		madt_end = (void *) (unsigned long)madt + madt->header.length;
-
-		entry = (struct acpi_table_int_src_ovr *)
-                ((unsigned long) madt + sizeof(struct acpi_table_madt));
-
-		while ((void *) entry < madt_end) {
-                	if (entry->header.type == ACPI_MADT_INT_SRC_OVR &&
-			    acpi_fadt.sci_int == entry->bus_irq)
-				goto found;
-			
-                	entry = (struct acpi_table_int_src_ovr *)
-                	        ((unsigned long) entry + entry->header.length);
-        	}
-	}
-	/*
-	 * Although the ACPI spec says that the SCI should be level/low
-	 * don't reprogram it unless there is an explicit MADT OVR entry
-	 * instructing us to do so -- otherwise we break Tyan boards which
-	 * have the SCI wired edge/high but no MADT OVR.
-	 */
-	return;
-
-found:
-	/*
-	 * See the note at the end of ACPI 2.0b section
-	 * 5.2.10.8 for what this is about.
-	 */
-	flags = entry->flags;
-	acpi_fadt.sci_int = entry->global_irq;
-	irq = entry->global_irq;
-
-	ioapic = mp_find_ioapic(irq);
-
-	ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
-
-	/*
-	 * MPS INTI flags:
-	 *  trigger: 0=default, 1=edge, 3=level
-	 *  polarity: 0=default, 1=high, 3=low
-	 * Per ACPI spec, default for SCI means level/low.
-	 */
-	io_apic_set_pci_routing(ioapic, ioapic_pin, irq, 
-		(flags.trigger == 1 ? 0 : 1), (flags.polarity == 1 ? 0 : 1));
-}
-
 #ifdef CONFIG_ACPI_PCI
 
 void __init mp_parse_prt (void)
@@ -949,7 +898,7 @@
 	struct acpi_prt_entry	*entry = NULL;
 	int			ioapic = -1;
 	int			ioapic_pin = 0;
-	int			irq = 0;
+	int			gsi = 0;
 	int			idx, bit = 0;
 	int			edge_level = 0;
 	int			active_high_low = 0;
@@ -961,30 +910,30 @@
 	list_for_each(node, &acpi_prt.entries) {
 		entry = list_entry(node, struct acpi_prt_entry, node);
 
-		/* Need to get irq for dynamic entry */
+		/* Need to get gsi for dynamic entry */
 		if (entry->link.handle) {
-			irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
-			if (!irq)
+			gsi = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low);
+			if (!gsi)
 				continue;
 		} else {
-			/* Hardwired IRQ. Assume PCI standard settings */
-			irq = entry->link.index;
+			/* Hardwired GSI. Assume PCI standard settings */
+			gsi = entry->link.index;
 			edge_level = 1;
 			active_high_low = 1;
 		}
 
 		/* Don't set up the ACPI SCI because it's already set up */
-		if (acpi_fadt.sci_int == irq)
+		if (acpi_fadt.sci_int == gsi)
 			continue;
 
-		ioapic = mp_find_ioapic(irq);
+		ioapic = mp_find_ioapic(gsi);
 		if (ioapic < 0)
 			continue;
-		ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
+		ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
 
 		/* 
 		 * Avoid pin reprogramming.  PRTs typically include entries  
-		 * with redundant pin->irq mappings (but unique PCI devices);
+		 * with redundant pin->gsi mappings (but unique PCI devices);
 		 * we only only program the IOAPIC on the first.
 		 */
 		bit = ioapic_pin % 32;
@@ -998,20 +947,16 @@
 		if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
 			Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
 				mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
- 			if (use_pci_vector() && !platform_legacy_irq(irq))
- 				irq = IO_APIC_VECTOR(irq);
-			entry->irq = irq;
+			acpi_gsi_to_irq(gsi, &entry->irq);
 			continue;
 		}
 
 		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
-		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq, edge_level, active_high_low)) {
- 			if (use_pci_vector() && !platform_legacy_irq(irq))
- 				irq = IO_APIC_VECTOR(irq);
-			entry->irq = irq;
+		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, edge_level, active_high_low)) {
+			acpi_gsi_to_irq(gsi, &entry->irq);
  		}
-		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d"
-			" -> IRQ %d\n", entry->id.segment, entry->id.bus, 
+		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
+			entry->id.segment, entry->id.bus,
 			entry->id.device, ('A' + entry->pin), 
 			mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
 			entry->irq);
diff -Nru a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
--- a/arch/x86_64/kernel/pci-gart.c	Sat Apr  3 19:38:43 2004
+++ b/arch/x86_64/kernel/pci-gart.c	Sat Apr  3 19:38:43 2004
@@ -21,6 +21,7 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/topology.h>
+#include <linux/interrupt.h>
 #include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/mtrr.h>
@@ -31,6 +32,12 @@
 #include <asm/kdebug.h>
 #include <asm/proto.h>
 
+#ifdef CONFIG_PREEMPT
+#define preempt_atomic() in_atomic()
+#else
+#define preempt_atomic() 1
+#endif
+
 dma_addr_t bad_dma_address;
 
 unsigned long iommu_bus_base;	/* GART remapping area (physical) */
@@ -50,6 +57,12 @@
 #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
@@ -90,6 +103,8 @@
 
 static unsigned long next_bit;  /* protected by iommu_bitmap_lock */
 static int need_flush; 		/* global flush state. set for each gart wrap */
+static dma_addr_t pci_map_area(struct pci_dev *dev, unsigned long phys_mem, 
+			       size_t size, int dir);
 
 static unsigned long alloc_iommu(int size) 
 { 	
@@ -163,43 +178,44 @@
 
 /* 
  * Allocate memory for a consistent mapping.
- * All mappings are consistent here, so this is just a wrapper around
- * pci_map_single.
  */
 void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 			   dma_addr_t *dma_handle)
 {
 	void *memory;
-	int gfp = GFP_ATOMIC;
-	unsigned long dma_mask;
-
-	if (hwdev == NULL) {
-		gfp |= GFP_DMA; 
-		dma_mask = 0xffffffff; 
-	} else {
-		dma_mask = hwdev->consistent_dma_mask; 
-	}
+	int gfp = preempt_atomic() ? GFP_ATOMIC : GFP_KERNEL; 
+	unsigned long dma_mask = 0;
+	u64 bus;
 
+	if (hwdev) 
+		dma_mask = hwdev->dev.coherent_dma_mask;
 	if (dma_mask == 0) 
 		dma_mask = 0xffffffff; 
-	if (dma_mask < 0xffffffff || no_iommu)
-		gfp |= GFP_DMA;
 
 	/* Kludge to make it bug-to-bug compatible with i386. i386
 	   uses the normal dma_mask for alloc_consistent. */
 	dma_mask &= hwdev->dma_mask;
 
+ again:
 	memory = (void *)__get_free_pages(gfp, get_order(size));
-	if (memory == NULL) {
+	if (memory == NULL)
 		return NULL; 
-	} else {
+
+	{
 		int high, mmu;
-	        high = ((unsigned long)virt_to_bus(memory) + size) >= dma_mask;
+		bus = virt_to_bus(memory);
+	        high = (bus + size) >= dma_mask;
 		mmu = high;
 		if (force_iommu && !(gfp & GFP_DMA)) 
 			mmu = 1;
-		if (no_iommu) { 
-			if (high) goto error;
+		if (no_iommu || dma_mask < 0xffffffffUL) { 
+			if (high) {
+				if (!(gfp & GFP_DMA)) { 
+					gfp |= GFP_DMA; 
+					goto again;
+				}
+				goto free;
+			}
 			mmu = 0; 
 		} 	
 		memset(memory, 0, size); 
@@ -209,15 +225,16 @@
 		}
 	} 
 
-	*dma_handle = pci_map_single(hwdev, memory, size, 0);
+	*dma_handle = pci_map_area(hwdev, bus, size, PCI_DMA_BIDIRECTIONAL);
 	if (*dma_handle == bad_dma_address)
 		goto error; 
-
+	flush_gart(hwdev);	
 	return memory; 
 	
 error:
 	if (panic_on_overflow)
-		panic("pci_map_single: overflow %lu bytes\n", size); 
+		panic("pci_alloc_consistent: overflow %lu bytes\n", size); 
+free:
 	free_pages((unsigned long)memory, get_order(size)); 
 	return NULL; 
 }
@@ -602,6 +619,7 @@
 EXPORT_SYMBOL(pci_dma_supported);
 EXPORT_SYMBOL(no_iommu);
 EXPORT_SYMBOL(force_iommu); 
+EXPORT_SYMBOL(bad_dma_address);
 
 static __init unsigned long check_iommu_size(unsigned long aper, u64 aper_size)
 { 
@@ -727,7 +745,7 @@
 
 	if (swiotlb) { 
 		no_iommu = 1;
-		printk(KERN_INFO "PCI-DMA: Using SWIOTLB :-(\n"); 
+		printk(KERN_INFO "PCI-DMA: Using software bounce buffering for  IO (SWIOTLB)\n"); 
 		return -1; 
 	} 
 	
@@ -831,6 +849,7 @@
    forcesac For SAC mode for masks <40bits  (experimental)
    fullflush Flush IOMMU on each allocation (default) 
    nofullflush Don't use IOMMU fullflush
+   soft	 Use software bounce buffering (default for Intel machines)
 */
 __init int iommu_setup(char *opt) 
 { 
@@ -870,6 +889,8 @@
 		    iommu_fullflush = 1;
 	    if (!memcmp(p, "nofullflush", 11))
 		    iommu_fullflush = 0;
+	    if (!memcmp(p, "soft", 4))
+		    swiotlb = 1;
 #ifdef CONFIG_IOMMU_LEAK
 	    if (!memcmp(p,"leak", 4)) { 
 		    leak_trace = 1;
diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
--- a/arch/x86_64/kernel/process.c	Sat Apr  3 19:38:44 2004
+++ b/arch/x86_64/kernel/process.c	Sat Apr  3 19:38:44 2004
@@ -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>
@@ -34,6 +32,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/ptrace.h>
+#include <linux/version.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -53,7 +52,7 @@
 
 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 +61,14 @@
 
 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 +79,7 @@
  */
 void default_idle(void)
 {
-	if (!hlt_counter) {
+	if (!atomic_read(&hlt_counter)) {
 		local_irq_disable();
 		if (!need_resched())
 			safe_halt();
@@ -207,7 +206,8 @@
 
 	printk("\n");
 	print_modules();
-	printk("Pid: %d, comm: %.20s %s\n", current->pid, current->comm, print_tainted());
+	printk("Pid: %d, comm: %.20s %s %s\n", 
+	       current->pid, current->comm, print_tainted(), UTS_RELEASE);
 	printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
 	printk_address(regs->rip); 
 	printk("\nRSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->rsp, regs->eflags);
diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
--- a/arch/x86_64/kernel/setup.c	Sat Apr  3 19:38:41 2004
+++ b/arch/x86_64/kernel/setup.c	Sat Apr  3 19:38:41 2004
@@ -68,6 +68,7 @@
 
 #ifdef	CONFIG_ACPI_BOOT
 extern int __initdata acpi_ht;
+extern acpi_interrupt_flags	acpi_sci_flags;
 /* int __initdata acpi_force = 0; */
 #endif
 
@@ -201,7 +202,18 @@
 	for (;;) {
 		if (c != ' ') 
 			goto next_char; 
- 
+
+#ifdef  CONFIG_SMP
+		/*
+		 * If the BIOS enumerates physical processors before logical,
+		 * maxcpus=N at enumeration-time can be used to disable HT.
+		 */
+		else if (!memcmp(from, "maxcpus=", 8)) {
+			extern unsigned int maxcpus;
+
+			maxcpus = simple_strtoul(from + 8, NULL, 0);
+		}
+#endif
 #ifdef CONFIG_ACPI_BOOT
 		/* "acpi=off" disables both ACPI table parsing and interpreter init */
 		if (!memcmp(from, "acpi=off", 8))
@@ -218,6 +230,22 @@
 		if (!memcmp(from, "acpi=ht", 7)) { 
 			acpi_ht = 1; 
 		}
+                else if (!memcmp(from, "pci=noacpi", 10)) 
+                        acpi_noirq_set();
+
+		else if (!memcmp(from, "acpi_sci=edge", 13))
+			acpi_sci_flags.trigger =  1;
+		else if (!memcmp(from, "acpi_sci=level", 14))
+			acpi_sci_flags.trigger = 3;
+		else if (!memcmp(from, "acpi_sci=high", 13))
+			acpi_sci_flags.polarity = 1;
+		else if (!memcmp(from, "acpi_sci=low", 12))
+			acpi_sci_flags.polarity = 3;
+
+		/* acpi=strict disables out-of-spec workarounds */
+		else if (!memcmp(from, "acpi=strict", 11)) {
+			acpi_strict = 1;
+		}
 #endif
 
 		if (!memcmp(from, "nolapic", 7) ||
@@ -227,7 +255,7 @@
 		if (!memcmp(from, "noapic", 6)) 
 			skip_ioapic_setup = 1;
 
-		if (!memcmp(from, "apic", 6)) { 
+		if (!memcmp(from, "apic", 4)) { 
 			skip_ioapic_setup = 0;
 			ioapic_force = 1;
 		}
@@ -448,9 +476,7 @@
 	paging_init();
 
 #ifndef CONFIG_SMP
-	/* Temporary hack: disable the IO-APIC for UP Nvidia and 
-	   This is until we sort out the ACPI problems. */
-	if (!acpi_disabled) 
+	/* Temporary hack: disable the IO-APIC for UP Nvidia and VIA. */
 		check_ioapic();
 #endif
 #ifdef CONFIG_ACPI_BOOT
@@ -591,8 +617,6 @@
 static void __init detect_ht(void)
 {
 #ifdef CONFIG_SMP
-	extern	int phys_proc_id[NR_CPUS];
-	
 	u32 	eax, ebx, ecx, edx;
 	int 	index_lsb, index_msb, tmp;
 	int	initial_apic_id;
@@ -793,13 +817,12 @@
 	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 +830,7 @@
 	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 +840,7 @@
 	      (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 +862,17 @@
 		/* 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 +890,6 @@
 			c->x86_capability[2] = cpuid_edx(0x80860001);
 	}
 
-
 	/*
 	 * Vendor-specific initialization.  In this section we
 	 * canonicalize the feature flags, meaning if there are
@@ -995,7 +1030,6 @@
 	
 #ifdef CONFIG_X86_HT
 	if (cpu_has_ht) {
-		extern int phys_proc_id[NR_CPUS];
 		seq_printf(m, "physical id\t: %d\n", phys_proc_id[c - cpu_data]);
 		seq_printf(m, "siblings\t: %d\n", smp_num_siblings);
 	}
diff -Nru a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
--- a/arch/x86_64/kernel/setup64.c	Sat Apr  3 19:38:42 2004
+++ b/arch/x86_64/kernel/setup64.c	Sat Apr  3 19:38:42 2004
@@ -202,7 +202,7 @@
 	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 @@
 
 	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 @@
 	 */
 	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 -Nru a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
--- a/arch/x86_64/kernel/smpboot.c	Sat Apr  3 19:38:57 2004
+++ b/arch/x86_64/kernel/smpboot.c	Sat Apr  3 19:38:57 2004
@@ -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 @@
 /* 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 @@
 	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 @@
 					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 -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
--- a/arch/x86_64/kernel/traps.c	Sat Apr  3 19:38:40 2004
+++ b/arch/x86_64/kernel/traps.c	Sat Apr  3 19:38:40 2004
@@ -351,24 +351,19 @@
 
 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 +470,29 @@
 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 void *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 regs; \
+	if (regs->cs & 3) { \
+		memcpy(pr, regs, sizeof(struct pt_regs)); \
+		regs = pr; \
+	} \
+	do_trap(trapnr, signr, str, regs, error_code, NULL); \
+	return regs;		\
+}
+
+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 +606,20 @@
 	inb(0x71);		/* dummy */
 }
 
-asmlinkage void do_debug(struct pt_regs * regs, long error_code)
+/* runs on IST stack. */
+asmlinkage void *do_debug(struct pt_regs * regs, unsigned long error_code)
 {
+	struct pt_regs *pr;
 	unsigned long condition;
 	struct task_struct *tsk = current;
 	siginfo_t info;
 
+	pr = (struct pt_regs *)(current->thread.rsp0)-1;
+	if (regs->cs & 3) {
+		memcpy(pr, regs, sizeof(struct pt_regs));
+		regs = pr;
+	}	
+
 #ifdef CONFIG_CHECKING
        { 
 	       /* RED-PEN interaction with debugger - could destroy gs */
@@ -658,17 +676,19 @@
 	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);
+	return regs;
 
 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;
+	return regs;	
 }
 
 /*
@@ -730,7 +750,7 @@
 	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 +809,7 @@
 	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 +837,6 @@
 	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 +845,7 @@
 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 +862,7 @@
 	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 -Nru a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
--- a/arch/x86_64/kernel/vsyscall.c	Sat Apr  3 19:38:54 2004
+++ b/arch/x86_64/kernel/vsyscall.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 			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 @@
 		*tz = __sys_tz;
 }
 
+
 static force_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
 {
 	int ret;
@@ -115,6 +113,15 @@
 	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 @@
 	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 -Nru a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
--- a/arch/x86_64/kernel/x8664_ksyms.c	Sat Apr  3 19:38:41 2004
+++ b/arch/x86_64/kernel/x8664_ksyms.c	Sat Apr  3 19:38:41 2004
@@ -63,10 +63,6 @@
 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 @@
 #endif
 
 EXPORT_SYMBOL(sys_ioctl);
+
+EXPORT_SYMBOL(memcpy_toio);
+EXPORT_SYMBOL(memcpy_fromio);
diff -Nru a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile
--- a/arch/x86_64/lib/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/x86_64/lib/Makefile	Sat Apr  3 19:38:41 2004
@@ -9,5 +9,4 @@
 	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
diff -Nru a/arch/x86_64/lib/csum-copy.S b/arch/x86_64/lib/csum-copy.S
--- a/arch/x86_64/lib/csum-copy.S	Sat Apr  3 19:38:55 2004
+++ b/arch/x86_64/lib/csum-copy.S	Sat Apr  3 19:38:55 2004
@@ -220,10 +220,14 @@
 	/* 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 -Nru a/arch/x86_64/lib/io.c b/arch/x86_64/lib/io.c
--- a/arch/x86_64/lib/io.c	Sat Apr  3 19:38:41 2004
+++ b/arch/x86_64/lib/io.c	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/arch/x86_64/lib/iodebug.c b/arch/x86_64/lib/iodebug.c
--- a/arch/x86_64/lib/iodebug.c	Sat Apr  3 19:38:44 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
--- a/arch/x86_64/mm/fault.c	Sat Apr  3 19:38:40 2004
+++ b/arch/x86_64/mm/fault.c	Sat Apr  3 19:38:40 2004
@@ -280,15 +280,6 @@
 	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);
 
@@ -371,6 +362,16 @@
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
 		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)) { 
diff -Nru a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
--- a/arch/x86_64/mm/init.c	Sat Apr  3 19:38:41 2004
+++ b/arch/x86_64/mm/init.c	Sat Apr  3 19:38:41 2004
@@ -37,7 +37,9 @@
 #include <asm/proto.h>
 #include <asm/smp.h>
 
+#ifndef Dprintk
 #define Dprintk(x...)
+#endif
 
 extern char _stext[];
 
@@ -403,10 +405,10 @@
 	int tmp;
 
 #ifdef CONFIG_SWIOTLB
-       if (!iommu_aperture && end_pfn >= 0xffffffff>>PAGE_SHIFT) { 
-	       swiotlb_init();
+	if (!iommu_aperture && end_pfn >= 0xffffffff>>PAGE_SHIFT)
 	       swiotlb = 1;
-       }
+	if (swiotlb)
+		swiotlb_init();	
 #endif
 
 	/* How many end-of-memory variables you have, grandma! */
@@ -577,3 +579,32 @@
 }
 __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 -Nru a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
--- a/arch/x86_64/mm/numa.c	Sat Apr  3 19:38:55 2004
+++ b/arch/x86_64/mm/numa.c	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile
--- a/arch/x86_64/pci/Makefile	Sat Apr  3 19:38:41 2004
+++ b/arch/x86_64/pci/Makefile	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/x86_64/pci/mmconfig.c	Sat Apr  3 19:38:57 2004
@@ -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 %x\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 -Nru a/crypto/Kconfig b/crypto/Kconfig
--- a/crypto/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/crypto/Kconfig	Sat Apr  3 19:38:55 2004
@@ -161,6 +161,15 @@
 	  
 	  You will most probably want this if using IPSec.
 
+config CRYPTO_MICHAEL_MIC
+	tristate "Michael MIC keyed digest algorithm"
+	depends on CRYPTO
+	help
+	  Michael MIC is used for message integrity protection in TKIP
+	  (IEEE 802.11i). This algorithm is required for TKIP, but it
+	  should not be used for other purposes because of the weakness
+	  of the algorithm.
+
 config CRYPTO_TEST
 	tristate "Testing module"
 	depends on CRYPTO
diff -Nru a/crypto/Makefile b/crypto/Makefile
--- a/crypto/Makefile	Sat Apr  3 19:38:56 2004
+++ b/crypto/Makefile	Sat Apr  3 19:38:56 2004
@@ -23,5 +23,6 @@
 obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
 obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
+obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
diff -Nru a/crypto/arc4.c b/crypto/arc4.c
--- a/crypto/arc4.c	Sat Apr  3 19:38:41 2004
+++ b/crypto/arc4.c	Sat Apr  3 19:38:41 2004
@@ -45,10 +45,6 @@
 			k = 0;
 	}
 
-	/* TODO: dump the first 768 bytes generated as recommended
-	   by Ilya Mironov (http://eprint.iacr.org/2002/067/) to 
-	   increase the statistical strength of the state table */
-
 	return 0;
 }
 
diff -Nru a/crypto/digest.c b/crypto/digest.c
--- a/crypto/digest.c	Sat Apr  3 19:38:40 2004
+++ b/crypto/digest.c	Sat Apr  3 19:38:40 2004
@@ -42,6 +42,15 @@
 	tfm->__crt_alg->cra_digest.dia_final(crypto_tfm_ctx(tfm), out);
 }
 
+static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+	u32 flags;
+	if (tfm->__crt_alg->cra_digest.dia_setkey == NULL)
+		return -ENOSYS;
+	return tfm->__crt_alg->cra_digest.dia_setkey(crypto_tfm_ctx(tfm),
+						     key, keylen, &flags);
+}
+
 static void digest(struct crypto_tfm *tfm,
                    struct scatterlist *sg, unsigned int nsg, u8 *out)
 {
@@ -72,6 +81,7 @@
 	ops->dit_update	= update;
 	ops->dit_final	= final;
 	ops->dit_digest	= digest;
+	ops->dit_setkey	= setkey;
 	
 	return crypto_alloc_hmac_block(tfm);
 }
diff -Nru a/crypto/michael_mic.c b/crypto/michael_mic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/crypto/michael_mic.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,193 @@
+/*
+ * Cryptographic API
+ *
+ * Michael MIC (IEEE 802.11i/TKIP) keyed digest
+ *
+ * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+
+
+struct michael_mic_ctx {
+	u8 pending[4];
+	size_t pending_len;
+
+	u32 l, r;
+};
+
+
+static inline u32 rotl(u32 val, int bits)
+{
+	return (val << bits) | (val >> (32 - bits));
+}
+
+
+static inline u32 rotr(u32 val, int bits)
+{
+	return (val >> bits) | (val << (32 - bits));
+}
+
+
+static inline u32 xswap(u32 val)
+{
+	return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8);
+}
+
+
+#define michael_block(l, r)	\
+do {				\
+	r ^= rotl(l, 17);	\
+	l += r;			\
+	r ^= xswap(l);		\
+	l += r;			\
+	r ^= rotl(l, 3);	\
+	l += r;			\
+	r ^= rotr(l, 2);	\
+	l += r;			\
+} while (0)
+
+
+static inline u32 get_le32(const u8 *p)
+{
+	return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+}
+
+
+static inline void put_le32(u8 *p, u32 v)
+{
+	p[0] = v;
+	p[1] = v >> 8;
+	p[2] = v >> 16;
+	p[3] = v >> 24;
+}
+
+
+static void michael_init(void *ctx)
+{
+	struct michael_mic_ctx *mctx = ctx;
+	mctx->pending_len = 0;
+}
+
+
+static void michael_update(void *ctx, const u8 *data, unsigned int len)
+{
+	struct michael_mic_ctx *mctx = ctx;
+
+	if (mctx->pending_len) {
+		int flen = 4 - mctx->pending_len;
+		if (flen > len)
+			flen = len;
+		memcpy(&mctx->pending[mctx->pending_len], data, flen);
+		mctx->pending_len += flen;
+		data += flen;
+		len -= flen;
+
+		if (mctx->pending_len < 4)
+			return;
+
+		mctx->l ^= get_le32(mctx->pending);
+		michael_block(mctx->l, mctx->r);
+		mctx->pending_len = 0;
+	}
+
+	while (len >= 4) {
+		mctx->l ^= get_le32(data);
+		michael_block(mctx->l, mctx->r);
+		data += 4;
+		len -= 4;
+	}
+
+	if (len > 0) {
+		mctx->pending_len = len;
+		memcpy(mctx->pending, data, len);
+	}
+}
+
+
+static void michael_final(void *ctx, u8 *out)
+{
+	struct michael_mic_ctx *mctx = ctx;
+	u8 *data = mctx->pending;
+
+	/* Last block and padding (0x5a, 4..7 x 0) */
+	switch (mctx->pending_len) {
+	case 0:
+		mctx->l ^= 0x5a;
+		break;
+	case 1:
+		mctx->l ^= data[0] | 0x5a00;
+		break;
+	case 2:
+		mctx->l ^= data[0] | (data[1] << 8) | 0x5a0000;
+		break;
+	case 3:
+		mctx->l ^= data[0] | (data[1] << 8) | (data[2] << 16) |
+			0x5a000000;
+		break;
+	}
+	michael_block(mctx->l, mctx->r);
+	/* l ^= 0; */
+	michael_block(mctx->l, mctx->r);
+
+	put_le32(out, mctx->l);
+	put_le32(out + 4, mctx->r);
+}
+
+
+static int michael_setkey(void *ctx, const u8 *key, unsigned int keylen,
+			  u32 *flags)
+{
+	struct michael_mic_ctx *mctx = ctx;
+	if (keylen != 8) {
+		if (flags)
+			*flags = CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	}
+	mctx->l = get_le32(key);
+	mctx->r = get_le32(key + 4);
+	return 0;
+}
+
+
+static struct crypto_alg michael_mic_alg = {
+	.cra_name	= "michael_mic",
+	.cra_flags	= CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize	= 8,
+	.cra_ctxsize	= sizeof(struct michael_mic_ctx),
+	.cra_module	= THIS_MODULE,
+	.cra_list	= LIST_HEAD_INIT(michael_mic_alg.cra_list),
+	.cra_u		= { .digest = {
+	.dia_digestsize	= 8,
+	.dia_init	= michael_init,
+	.dia_update	= michael_update,
+	.dia_final	= michael_final,
+	.dia_setkey	= michael_setkey } }
+};
+
+
+static int __init michael_mic_init(void)
+{
+	return crypto_register_alg(&michael_mic_alg);
+}
+
+
+static void __exit michael_mic_exit(void)
+{
+	crypto_unregister_alg(&michael_mic_alg);
+}
+
+
+module_init(michael_mic_init);
+module_exit(michael_mic_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Michael MIC");
+MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
diff -Nru a/crypto/tcrypt.c b/crypto/tcrypt.c
--- a/crypto/tcrypt.c	Sat Apr  3 19:38:55 2004
+++ b/crypto/tcrypt.c	Sat Apr  3 19:38:55 2004
@@ -61,7 +61,7 @@
 static char *check[] = {
 	"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
 	"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6", 
-	"arc4", "deflate", NULL
+	"arc4", "michael_mic", "deflate", NULL
 };
 
 static void
@@ -112,6 +112,10 @@
 		sg[0].length = hash_tv[i].psize;
 
 		crypto_digest_init (tfm);
+		if (tfm->crt_u.digest.dit_setkey) {
+			crypto_digest_setkey (tfm, hash_tv[i].key,
+					      hash_tv[i].ksize);
+		}
 		crypto_digest_update (tfm, sg, 1);
 		crypto_digest_final (tfm, result);
 
@@ -558,7 +562,7 @@
 
 		//ARC4
 		test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS);
-		test_cipher ("arc4x", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS);
+		test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS);
 
 		test_hash("sha384", sha384_tv_template, SHA384_TEST_VECTORS);
 		test_hash("sha512", sha512_tv_template, SHA512_TEST_VECTORS);
@@ -568,6 +572,8 @@
 		test_hmac("sha1", hmac_sha1_tv_template, HMAC_SHA1_TEST_VECTORS);		
 		test_hmac("sha256", hmac_sha256_tv_template, HMAC_SHA256_TEST_VECTORS);
 #endif		
+
+		test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
 		break;
 
 	case 1:
@@ -645,6 +651,10 @@
 	case 16:
 		test_cipher ("arc4", MODE_ECB, ENCRYPT, arc4_enc_tv_template, ARC4_ENC_TEST_VECTORS);
 		test_cipher ("arc4", MODE_ECB, DECRYPT, arc4_dec_tv_template, ARC4_DEC_TEST_VECTORS);
+		break;
+
+	case 17:
+		test_hash("michael_mic", michael_mic_tv_template, MICHAEL_MIC_TEST_VECTORS);
 		break;
 
 #ifdef CONFIG_CRYPTO_HMAC
diff -Nru a/crypto/tcrypt.h b/crypto/tcrypt.h
--- a/crypto/tcrypt.h	Sat Apr  3 19:38:55 2004
+++ b/crypto/tcrypt.h	Sat Apr  3 19:38:55 2004
@@ -30,6 +30,8 @@
 	char digest[MAX_DIGEST_SIZE];
 	unsigned char np;
 	unsigned char tap[MAX_TAP];		
+	char key[128]; /* only used with keyed hash algorithms */
+	unsigned char ksize;
 };
 
 struct hmac_testvec {	
@@ -1719,4 +1721,54 @@
 	},
 };
 
+/*
+ * Michael MIC test vectors from IEEE 802.11i
+ */
+#define MICHAEL_MIC_TEST_VECTORS 6
+
+struct hash_testvec michael_mic_tv_template[] =
+{
+	{
+		.key = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		.ksize = 8,
+		.plaintext = { },
+		.psize = 0,
+		.digest = { 0x82, 0x92, 0x5c, 0x1c, 0xa1, 0xd1, 0x30, 0xb8 }
+	},
+	{
+		.key = { 0x82, 0x92, 0x5c, 0x1c, 0xa1, 0xd1, 0x30, 0xb8 },
+		.ksize = 8,
+		.plaintext = { 'M' },
+		.psize = 1,
+		.digest = { 0x43, 0x47, 0x21, 0xca, 0x40, 0x63, 0x9b, 0x3f }
+	},
+	{
+		.key = { 0x43, 0x47, 0x21, 0xca, 0x40, 0x63, 0x9b, 0x3f },
+		.ksize = 8,
+		.plaintext = { 'M', 'i' },
+		.psize = 2,
+		.digest = { 0xe8, 0xf9, 0xbe, 0xca, 0xe9, 0x7e, 0x5d, 0x29 }
+	},
+	{
+		.key = { 0xe8, 0xf9, 0xbe, 0xca, 0xe9, 0x7e, 0x5d, 0x29 },
+		.ksize = 8,
+		.plaintext = { 'M', 'i', 'c' },
+		.psize = 3,
+		.digest = { 0x90, 0x03, 0x8f, 0xc6, 0xcf, 0x13, 0xc1, 0xdb }
+	},
+	{
+		.key = { 0x90, 0x03, 0x8f, 0xc6, 0xcf, 0x13, 0xc1, 0xdb },
+		.ksize = 8,
+		.plaintext = { 'M', 'i', 'c', 'h' },
+		.psize = 4,
+		.digest = { 0xd5, 0x5e, 0x10, 0x05, 0x10, 0x12, 0x89, 0x86 }
+	},
+	{
+		.key = { 0xd5, 0x5e, 0x10, 0x05, 0x10, 0x12, 0x89, 0x86 },
+		.ksize = 8,
+		.plaintext = { 'M', 'i', 'c', 'h', 'a', 'e', 'l' },
+		.psize = 7,
+		.digest = { 0x0a, 0x94, 0x2b, 0x12, 0x4e, 0xca, 0xa5, 0x46 },
+	}
+};
 #endif	/* _CRYPTO_TCRYPT_H */
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	Sat Apr  3 19:38:55 2004
+++ b/drivers/Makefile	Sat Apr  3 19:38:55 2004
@@ -49,3 +49,4 @@
 obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
+obj-y				+= firmware/
diff -Nru a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile
--- a/drivers/acorn/char/Makefile	Sat Apr  3 19:38:41 2004
+++ b/drivers/acorn/char/Makefile	Sat Apr  3 19:38:41 2004
@@ -4,4 +4,3 @@
 
 obj-$(CONFIG_ARCH_ACORN)	+= i2c.o pcf8583.o
 obj-$(CONFIG_L7200_KEYB)	+= defkeymap-l7200.o keyb_l7200.o
-obj-y				+= $(obj-$(MACHINE))
diff -Nru a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
--- a/drivers/acorn/char/i2c.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/acorn/char/i2c.c	Sat Apr  3 19:38:56 2004
@@ -34,9 +34,13 @@
 static struct i2c_client *rtc_client;
 static const unsigned char days_in_mon[] = 
 	{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-static unsigned int rtc_epoch = 1900;
 
 #define CMOS_CHECKSUM	(63)
+
+/*
+ * Acorn machines store the year in the static RAM at
+ * location 128.
+ */
 #define CMOS_YEAR	(64 + 128)
 
 static inline int rtc_command(int cmd, void *data)
@@ -50,51 +54,89 @@
 }
 
 /*
+ * Update the century + year bytes in the CMOS RAM, ensuring
+ * that the check byte is correctly adjusted for the change.
+ */
+static int rtc_update_year(unsigned int new_year)
+{
+	unsigned char yr[2], chk;
+	struct mem cmos_year  = { CMOS_YEAR, sizeof(yr), yr };
+	struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+	int ret;
+
+	ret = rtc_command(MEM_READ, &cmos_check);
+	if (ret)
+		goto out;
+	ret = rtc_command(MEM_READ, &cmos_year);
+	if (ret)
+		goto out;
+
+	chk -= yr[1] + yr[0];
+
+	yr[1] = new_year / 100;
+	yr[0] = new_year % 100;
+
+	chk += yr[1] + yr[0];
+
+	ret = rtc_command(MEM_WRITE, &cmos_year);
+	if (ret == 0)
+		ret = rtc_command(MEM_WRITE, &cmos_check);
+ out:
+	return ret;
+}
+
+/*
  * Read the current RTC time and date, and update xtime.
  */
 static void get_rtc_time(struct rtc_tm *rtctm, unsigned int *year)
 {
 	unsigned char ctrl, yr[2];
 	struct mem rtcmem = { CMOS_YEAR, sizeof(yr), yr };
+	int real_year, year_offset;
 
 	/*
 	 * Ensure that the RTC is running.
 	 */
 	rtc_command(RTC_GETCTRL, &ctrl);
 	if (ctrl & 0xc0) {
-		unsigned char new_ctrl;
-
-		new_ctrl = ctrl & ~0xc0;
+		unsigned char new_ctrl = ctrl & ~0xc0;
 
-		printk("RTC: resetting control %02X -> %02X\n",
+		printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
 		       ctrl, new_ctrl);
 
 		rtc_command(RTC_SETCTRL, &new_ctrl);
 	}
 
-	/*
-	 * Acorn machines store the year in
-	 * the static RAM at location 192.
-	 */
-	if (rtc_command(MEM_READ, &rtcmem))
+	if (rtc_command(RTC_GETDATETIME, rtctm) ||
+	    rtc_command(MEM_READ, &rtcmem))
 		return;
 
-	if (rtc_command(RTC_GETDATETIME, rtctm))
-		return;
+	real_year = yr[0];
 
-	*year = yr[1] * 100 + yr[0];
+	/*
+	 * The RTC year holds the LSB two bits of the current
+	 * year, which should reflect the LSB two bits of the
+	 * CMOS copy of the year.  Any difference indicates
+	 * that we have to correct the CMOS version.
+	 */
+	year_offset = rtctm->year_off - (real_year & 3);
+	if (year_offset < 0)
+		/*
+		 * RTC year wrapped.  Adjust it appropriately.
+		 */
+		year_offset += 4;
+
+	*year = real_year + year_offset + yr[1] * 100;
 }
 
 static int set_rtc_time(struct rtc_tm *rtctm, unsigned int year)
 {
-	unsigned char yr[2], leap, chk;
-	struct mem cmos_year  = { CMOS_YEAR, sizeof(yr), yr };
-	struct mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+	unsigned char leap;
 	int ret;
 
 	leap = (!(year % 4) && (year % 100)) || !(year % 400);
 
-	if (rtctm->mon > 12 || rtctm->mday == 0)
+	if (rtctm->mon > 12 || rtctm->mon == 0 || rtctm->mday == 0)
 		return -EINVAL;
 
 	if (rtctm->mday > (days_in_mon[rtctm->mon] + (rtctm->mon == 2 && leap)))
@@ -103,21 +145,16 @@
 	if (rtctm->hours >= 24 || rtctm->mins >= 60 || rtctm->secs >= 60)
 		return -EINVAL;
 
-	ret = rtc_command(RTC_SETDATETIME, rtctm);
-	if (ret == 0) {
-		rtc_command(MEM_READ, &cmos_check);
-		rtc_command(MEM_READ, &cmos_year);
-
-		chk -= yr[1] + yr[0];
-
-		yr[1] = year / 100;
-		yr[0] = year % 100;
+	/*
+	 * The RTC's own 2-bit year must reflect the least
+	 * significant two bits of the CMOS year.
+	 */
+	rtctm->year_off = (year % 100) & 3;
 
-		chk += yr[1] + yr[0];
+	ret = rtc_command(RTC_SETDATETIME, rtctm);
+	if (ret == 0)
+		ret = rtc_update_year(year);
 
-		rtc_command(MEM_WRITE, &cmos_year);
-		rtc_command(MEM_WRITE, &cmos_check);
-	}
 	return ret;
 }
 
@@ -189,13 +226,12 @@
 		rtc_raw.hours    = rtctm.tm_hour;
 		rtc_raw.mday     = rtctm.tm_mday;
 		rtc_raw.mon      = rtctm.tm_mon + 1;
-		rtc_raw.year_off = 2;
 		year             = rtctm.tm_year + 1900;
 		return set_rtc_time(&rtc_raw, year);
 		break;
 
 	case RTC_EPOCH_READ:
-		return put_user(rtc_epoch, (unsigned long *)arg);
+		return put_user(1900, (unsigned long *)arg);
 
 	}
 	return -EINVAL;
diff -Nru a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
--- a/drivers/acpi/Kconfig	Sat Apr  3 19:38:56 2004
+++ b/drivers/acpi/Kconfig	Sat Apr  3 19:38:56 2004
@@ -255,6 +255,7 @@
 	bool "Power Management Timer Support"
 	depends on X86 && ACPI
 	depends on ACPI_BOOT && EXPERIMENTAL
+	depends on !X86_64
 	default n
 	help
 	  The Power Management Timer is available on all ACPI-capable,
diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c
--- a/drivers/acpi/bus.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/acpi/bus.c	Sat Apr  3 19:38:44 2004
@@ -39,7 +39,9 @@
 #define _COMPONENT		ACPI_BUS_COMPONENT
 ACPI_MODULE_NAME		("acpi_bus")
 
-extern void __init acpi_pic_sci_set_trigger(unsigned int irq);
+#ifdef	CONFIG_X86
+extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
+#endif
 
 FADT_DESCRIPTOR			acpi_fadt;
 struct acpi_device		*acpi_root;
@@ -611,11 +613,23 @@
 	}
 
 #ifdef CONFIG_X86
-	/* Ensure the SCI is set to level-triggered, active-low */
-	if (acpi_ioapic)
-		mp_config_ioapic_for_sci(acpi_fadt.sci_int);
-	else
-		acpi_pic_sci_set_trigger(acpi_fadt.sci_int);
+	if (!acpi_ioapic) {
+		extern acpi_interrupt_flags acpi_sci_flags;
+
+		/* compatible (0) means level (3) */
+		if (acpi_sci_flags.trigger == 0)
+			acpi_sci_flags.trigger = 3;
+
+		/* Set PIC-mode SCI trigger type */
+		acpi_pic_sci_set_trigger(acpi_fadt.sci_int, acpi_sci_flags.trigger);
+	} else {
+		extern int acpi_sci_override_gsi;
+		/*
+		 * now that acpi_fadt is initialized,
+		 * update it with result from INT_SRC_OVR parsing
+		 */
+		acpi_fadt.sci_int = acpi_sci_override_gsi;
+	}
 #endif
 
 	status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
@@ -704,29 +718,14 @@
 			pm_active = 1;
 		else {
 			printk(KERN_INFO PREFIX "APM is already active, exiting\n");
-			acpi_disabled = 1;
+			disable_acpi();
 			result = -ENODEV;
 		}
 #endif
 	} else
-		acpi_disabled = 1;
+		disable_acpi();
 
 	return_VALUE(result);
 }
 
-
-static int __init acpi_setup(char *str)
-{
-	while (str && *str) {
-		if (strncmp(str, "off", 3) == 0)
-			acpi_disabled = 1;
-		str = strchr(str, ',');
-		if (str)
-			str += strspn(str, ", \t");
-	}
-	return 1;
-}
-
 subsys_initcall(acpi_init);
-
-__setup("acpi=", acpi_setup);
diff -Nru a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
--- a/drivers/acpi/dispatcher/dsmethod.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/dispatcher/dsmethod.c	Sat Apr  3 19:38:43 2004
@@ -106,7 +106,7 @@
 
 	/* 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 @@
 		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 @@
 		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_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,10 +511,30 @@
 		}
 	}
 
-	/* 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 -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c
--- a/drivers/acpi/ec.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/ec.c	Sat Apr  3 19:38:43 2004
@@ -719,7 +719,7 @@
 	 * Install GPE handler
 	 */
 	status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
-		ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec);
+		ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec);
 	if (ACPI_FAILURE(status)) {
 		return_VALUE(-ENODEV);
 	}
@@ -803,7 +803,7 @@
 	 * Install GPE handler
 	 */
 	status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
-		ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler,
+		ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler,
 		ec_ecdt);
 	if (ACPI_FAILURE(status)) {
 		goto error;
diff -Nru a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
--- a/drivers/acpi/events/evgpe.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/acpi/events/evgpe.c	Sat Apr  3 19:38:44 2004
@@ -99,9 +99,8 @@
 		return (NULL);
 	}
 
-	/*
-	 * A Non-null gpe_device means this is a GPE Block Device.
-	 */
+	/* A Non-NULL gpe_device means this is a GPE Block Device */
+
 	obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) gpe_device);
 	if (!obj_desc ||
 		!obj_desc->device.gpe_block) {
@@ -149,6 +148,11 @@
 
 	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 */
 
@@ -292,7 +296,7 @@
 		}
 	}
 
-	if (local_gpe_event_info.flags & ACPI_EVENT_LEVEL_TRIGGERED) {
+	if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) {
 		/*
 		 * GPE is level-triggered, we clear the GPE status bit after handling
 		 * the event.
@@ -341,7 +345,7 @@
 	 * If edge-triggered, clear the GPE status bit now.  Note that
 	 * level-triggered events are cleared after the GPE is serviced.
 	 */
-	if (gpe_event_info->flags & ACPI_EVENT_EDGE_TRIGGERED) {
+	if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) {
 		status = acpi_hw_clear_gpe (gpe_event_info);
 		if (ACPI_FAILURE (status)) {
 			ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to clear GPE[%2X]\n",
@@ -364,7 +368,7 @@
 
 		/* It is now safe to clear level-triggered events. */
 
-		if (gpe_event_info->flags & ACPI_EVENT_LEVEL_TRIGGERED) {
+		if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) {
 			status = acpi_hw_clear_gpe (gpe_event_info);
 			if (ACPI_FAILURE (status)) {
 				ACPI_REPORT_ERROR ((
diff -Nru a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
--- a/drivers/acpi/events/evgpeblk.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/events/evgpeblk.c	Sat Apr  3 19:38:43 2004
@@ -168,11 +168,11 @@
  *              information for quick lookup during GPE dispatch
  *
  *              The name of each GPE control method is of the form:
- *                  "_Lnn" or "_Enn"
- *                  Where:
- *                      L      - means that the GPE is level triggered
- *                      E      - means that the GPE is edge triggered
- *                      nn     - is the GPE number [in HEX]
+ *              "_Lxx" or "_Exx"
+ *              Where:
+ *                  L      - means that the GPE is level triggered
+ *                  E      - means that the GPE is edge triggered
+ *                  xx     - is the GPE number [in HEX]
  *
  ******************************************************************************/
 
@@ -188,36 +188,41 @@
 	u32                             gpe_number;
 	char                            name[ACPI_NAME_SIZE + 1];
 	u8                              type;
-	acpi_status                     status;
 
 
 	ACPI_FUNCTION_TRACE ("ev_save_method_info");
 
 
-	/* Extract the name from the object and convert to a string */
-
+	/*
+	 * _Lxx and _Exx GPE method support
+	 *
+	 * 1) Extract the name from the object and convert to a string
+	 */
 	ACPI_MOVE_32_TO_32 (name,
 			   &((struct acpi_namespace_node *) obj_handle)->name.integer);
 	name[ACPI_NAME_SIZE] = 0;
 
 	/*
-	 * Edge/Level determination is based on the 2nd character
-	 * of the method name
+	 * 2) Edge/Level determination is based on the 2nd character
+	 *    of the method name
+	 *
+	 * NOTE: Default GPE type is RUNTIME.  May be changed later to WAKE if a
+	 * _PRW object is found that points to this GPE.
 	 */
 	switch (name[1]) {
 	case 'L':
-		type = ACPI_EVENT_LEVEL_TRIGGERED;
+		type = ACPI_GPE_LEVEL_TRIGGERED | ACPI_GPE_TYPE_RUNTIME;
 		break;
 
 	case 'E':
-		type = ACPI_EVENT_EDGE_TRIGGERED;
+		type = ACPI_GPE_EDGE_TRIGGERED | ACPI_GPE_TYPE_RUNTIME;
 		break;
 
 	default:
 		/* Unknown method type, just ignore it! */
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-			"Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n",
+			"Unknown GPE method type: %s (name not of form _Lxx or _Exx)\n",
 			name));
 		return_ACPI_STATUS (AE_OK);
 	}
@@ -229,7 +234,7 @@
 		/* Conversion failed; invalid method, just ignore it */
 
 		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
-			"Could not extract GPE number from name: %s (name is not of form _Lnn or _Enn)\n",
+			"Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)\n",
 			name));
 		return_ACPI_STATUS (AE_OK);
 	}
@@ -255,13 +260,6 @@
 	gpe_event_info->flags    = type;
 	gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle;
 
-	/* Enable the GPE (SCIs should be disabled at this point) */
-
-	status = acpi_hw_enable_gpe (gpe_event_info);
-	if (ACPI_FAILURE (status)) {
-		return_ACPI_STATUS (status);
-	}
-
 	ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
 		"Registered GPE method %s as GPE number 0x%.2X\n",
 		name, gpe_number));
@@ -271,6 +269,122 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_ev_get_gpe_type
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
+ *              Device.  Run the _PRW method.  If present, extract the GPE
+ *              number and mark the GPE as a WAKE GPE.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_get_gpe_type (
+	acpi_handle                     obj_handle,
+	u32                             level,
+	void                            *info,
+	void                            **return_value)
+{
+	struct acpi_gpe_walk_info       *gpe_info = (void *) info;
+	struct acpi_namespace_node      *gpe_device;
+	struct acpi_gpe_block_info      *gpe_block;
+	struct acpi_namespace_node      *target_gpe_device;
+	struct acpi_gpe_event_info      *gpe_event_info;
+	union acpi_operand_object       *pkg_desc;
+	union acpi_operand_object       *obj_desc;
+	u32                             gpe_number;
+	acpi_status                     status;
+
+
+	ACPI_FUNCTION_TRACE ("ev_get_gpe_type");
+
+
+	/* Check for a _PRW method under this device */
+
+	status = acpi_ut_evaluate_object (obj_handle, METHOD_NAME__PRW,
+			 ACPI_BTYPE_PACKAGE, &pkg_desc);
+	if (status == AE_NOT_FOUND) {
+		return_ACPI_STATUS (AE_OK);
+	}
+	else if (ACPI_FAILURE (status)) {
+		return_ACPI_STATUS (status);
+	}
+
+	/* The returned _PRW package must have at least two elements */
+
+	if (pkg_desc->package.count < 2) {
+		goto cleanup;
+	}
+
+	/* Extract pointers from the input context */
+
+	gpe_device = gpe_info->gpe_device;
+	gpe_block = gpe_info->gpe_block;
+
+	/*
+	 * The _PRW object must return a package, we are only interested
+	 * in the first element
+	 */
+	obj_desc = pkg_desc->package.elements[0];
+
+	if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+		/* Use FADT-defined GPE device (from definition of _PRW) */
+
+		target_gpe_device = acpi_gbl_fadt_gpe_device;
+
+		/* Integer is the GPE number in the FADT described GPE blocks */
+
+		gpe_number = (u32) obj_desc->integer.value;
+	}
+	else if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) {
+		/* Package contains a GPE reference and GPE number within a GPE block */
+
+		if ((obj_desc->package.count < 2) ||
+			(ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[0]) != ACPI_TYPE_LOCAL_REFERENCE) ||
+			(ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) {
+			goto cleanup;
+		}
+
+		/* Get GPE block reference and decode */
+
+		target_gpe_device = obj_desc->package.elements[0]->reference.node;
+		gpe_number = (u32) obj_desc->package.elements[1]->integer.value;
+	}
+	else {
+		/* Unknown type, just ignore it */
+
+		goto cleanup;
+	}
+
+	/*
+	 * Is this GPE within this block?
+	 *
+	 * TRUE iff these conditions are true:
+	 *     1) The GPE devices match.
+	 *     2) The GPE index(number) is within the range of the Gpe Block
+	 *          associated with the GPE device.
+	 */
+	if ((gpe_device == target_gpe_device) &&
+		(gpe_number >= gpe_block->block_base_number) &&
+		(gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) {
+		/* Mark GPE for WAKE but DISABLED (even for wake) */
+
+		gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number];
+		gpe_event_info->flags |= ACPI_GPE_TYPE_WAKE;
+	}
+
+cleanup:
+	acpi_ut_remove_reference (pkg_desc);
+
+	return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ev_get_gpe_xrupt_block
  *
  * PARAMETERS:  interrupt_level     - Interrupt for a GPE block
@@ -695,8 +809,13 @@
 	struct acpi_gpe_block_info      **return_gpe_block)
 {
 	struct acpi_gpe_block_info      *gpe_block;
+	struct acpi_gpe_event_info      *gpe_event_info;
+	acpi_native_uint                i;
+	acpi_native_uint                j;
+	u32                             wake_gpe_count;
+	u32                             gpe_enabled_count;
 	acpi_status                     status;
-
+	struct acpi_gpe_walk_info       gpe_info;
 
 	ACPI_FUNCTION_TRACE ("ev_create_gpe_block");
 
@@ -737,7 +856,8 @@
 
 	/* Dump info about this GPE block */
 
-	ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n",
+	ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+		"GPE %02d to %02d [%4.4s] %d regs at %8.8X%8.8X on int %d\n",
 		gpe_block->block_base_number,
 		(u32) (gpe_block->block_base_number +
 				((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)),
@@ -752,6 +872,58 @@
 			  ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, acpi_ev_save_method_info,
 			  gpe_block, NULL);
 
+	/*
+	 * Runtime option: Should Wake GPEs be enabled at runtime?  The default is
+	 * No,they should only be enabled just as the machine goes to sleep.
+	 */
+	if (acpi_gbl_leave_wake_gpes_disabled) {
+		/*
+		 * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods. (Each
+		 * GPE that has one or more _PRWs that reference it is by definition a
+		 * WAKE GPE and will not be enabled while the machine is running.)
+		 */
+		gpe_info.gpe_block = gpe_block;
+		gpe_info.gpe_device = gpe_device;
+
+		status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+				  ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_get_gpe_type,
+				  &gpe_info, NULL);
+	}
+
+	/*
+	 * Enable all GPEs in this block that are 1) "runtime" GPEs, and 2) have
+	 * a corresponding _Lxx or _Exx method.  All other GPEs must be enabled via
+	 * the acpi_enable_gpe() external interface.
+	 */
+	wake_gpe_count = 0;
+	gpe_enabled_count = 0;
+
+	for (i = 0; i < gpe_block->register_count; i++) {
+		for (j = 0; j < 8; j++) {
+			/* Get the info block for this particular GPE */
+
+			gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j];
+			if ((gpe_event_info->method_node) &&
+			   ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_RUNTIME)) {
+				/* Enable this GPE, it is 1) RUNTIME and 2) has an _Lxx or _Exx method */
+
+				status = acpi_hw_enable_gpe (gpe_event_info);
+				if (ACPI_FAILURE (status)) {
+					return_ACPI_STATUS (status);
+				}
+				gpe_enabled_count++;
+			}
+
+			if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == ACPI_GPE_TYPE_WAKE) {
+				wake_gpe_count++;
+			}
+		}
+	}
+
+	ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+			"Found %u Wake, Enabled %u Runtime GPEs in this block\n",
+			wake_gpe_count, gpe_enabled_count));
+
 	/* Return the new block */
 
 	if (return_gpe_block) {
@@ -775,27 +947,25 @@
  ******************************************************************************/
 
 acpi_status
-acpi_ev_gpe_initialize (void)
+acpi_ev_gpe_initialize (
+	void)
 {
 	u32                             register_count0 = 0;
 	u32                             register_count1 = 0;
 	u32                             gpe_number_max = 0;
-	acpi_handle                     gpe_device;
 	acpi_status                     status;
 
 
 	ACPI_FUNCTION_TRACE ("ev_gpe_initialize");
 
 
-	/* Get a handle to the predefined _GPE object */
-
-	status = acpi_get_handle (NULL, "\\_GPE", &gpe_device);
+	status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
 
 	/*
-	 * Initialize the GPE Blocks defined in the FADT
+	 * Initialize the GPE Block(s) defined in the FADT
 	 *
 	 * Why the GPE register block lengths are divided by 2:  From the ACPI Spec,
 	 * section "General-Purpose Event Registers", we have:
@@ -829,8 +999,9 @@
 
 		/* Install GPE Block 0 */
 
-		status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe0_blk,
+		status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe0_blk,
 				 register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]);
+
 		if (ACPI_FAILURE (status)) {
 			ACPI_REPORT_ERROR ((
 				"Could not create GPE Block 0, %s\n",
@@ -861,9 +1032,10 @@
 		else {
 			/* Install GPE Block 1 */
 
-			status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe1_blk,
+			status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe1_blk,
 					 register_count1, acpi_gbl_FADT->gpe1_base,
 					 acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]);
+
 			if (ACPI_FAILURE (status)) {
 				ACPI_REPORT_ERROR ((
 					"Could not create GPE Block 1, %s\n",
@@ -885,7 +1057,8 @@
 		/* GPEs are not required by ACPI, this is OK */
 
 		ACPI_REPORT_INFO (("There are no GPE blocks defined in the FADT\n"));
-		return_ACPI_STATUS (AE_OK);
+		status = AE_OK;
+		goto cleanup;
 	}
 
 	/* Check for Max GPE number out-of-range */
@@ -893,9 +1066,12 @@
 	if (gpe_number_max > ACPI_GPE_MAX) {
 		ACPI_REPORT_ERROR (("Maximum GPE number from FADT is too large: 0x%X\n",
 			gpe_number_max));
-		return_ACPI_STATUS (AE_BAD_VALUE);
+		status = AE_BAD_VALUE;
+		goto cleanup;
 	}
 
+cleanup:
+	(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
 	return_ACPI_STATUS (AE_OK);
 }
 
diff -Nru a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
--- a/drivers/acpi/events/evmisc.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/acpi/events/evmisc.c	Sat Apr  3 19:38:44 2004
@@ -97,6 +97,20 @@
  *
  ******************************************************************************/
 
+#ifdef ACPI_DEBUG_OUTPUT
+static const char                *acpi_notify_value_names[] =
+{
+	"Bus Check",
+	"Device Check",
+	"Device Wake",
+	"Eject request",
+	"Device Check Light",
+	"Frequency Mismatch",
+	"Bus Mode Mismatch",
+	"Power Fault"
+};
+#endif
+
 acpi_status
 acpi_ev_queue_notify_request (
 	struct acpi_namespace_node      *node,
@@ -112,7 +126,7 @@
 
 
 	/*
-	 * For value 1 (Ejection Request), some device method may need to be run.
+	 * For value 3 (Ejection Request), some device method may need to be run.
 	 * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
 	 * For value 0x80 (Status Change) on the power button or sleep button,
 	 * initiate soft-off or sleep operation?
@@ -120,26 +134,13 @@
 	ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
 		"Dispatching Notify(%X) on node %p\n", notify_value, node));
 
-	switch (notify_value) {
-	case 0:
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Re-enumerate Devices\n"));
-		break;
-
-	case 1:
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Ejection Request\n"));
-		break;
-
-	case 2:
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Device Wake\n"));
-		break;
-
-	case 0x80:
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: Status Change\n"));
-		break;
-
-	default:
-		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unknown Notify Value: %X \n", notify_value));
-		break;
+	if (notify_value <= 7) {
+		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: %s\n",
+				acpi_notify_value_names[notify_value]));
+	}
+	else {
+		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "notify value: 0x2.2_x **Device Specific**\n",
+				notify_value));
 	}
 
 	/*
diff -Nru a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
--- a/drivers/acpi/events/evxfevnt.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/acpi/events/evxfevnt.c	Sat Apr  3 19:38:42 2004
@@ -247,16 +247,29 @@
 		goto unlock_and_exit;
 	}
 
-	/* Enable the requested GPE number */
-
-	status = acpi_hw_enable_gpe (gpe_event_info);
-	if (ACPI_FAILURE (status)) {
-		goto unlock_and_exit;
-	}
+	/* Check for Wake vs Runtime GPE */
 
 	if (flags & ACPI_EVENT_WAKE_ENABLE) {
+		/* Ensure the requested wake GPE is disabled */
+
+		status = acpi_hw_disable_gpe (gpe_event_info);
+		if (ACPI_FAILURE (status)) {
+			goto unlock_and_exit;
+		}
+
+		/* Defer Enable of Wake GPE until sleep time */
+
 		acpi_hw_enable_gpe_for_wakeup (gpe_event_info);
 	}
+	else {
+		/* Enable the requested runtime GPE  */
+
+		status = acpi_hw_enable_gpe (gpe_event_info);
+		if (ACPI_FAILURE (status)) {
+			goto unlock_and_exit;
+		}
+	}
+
 
 unlock_and_exit:
 	if (flags & ACPI_NOT_ISR) {
diff -Nru a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
--- a/drivers/acpi/executer/excreate.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/acpi/executer/excreate.c	Sat Apr  3 19:38:55 2004
@@ -84,14 +84,15 @@
 	alias_node = (struct acpi_namespace_node *) walk_state->operands[0];
 	target_node = (struct acpi_namespace_node *) walk_state->operands[1];
 
-	if (target_node->type == ACPI_TYPE_LOCAL_ALIAS) {
+	if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) ||
+		(target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
 		/*
 		 * Dereference an existing alias so that we don't create a chain
 		 * of aliases.  With this code, we guarantee that an alias is
 		 * always exactly one level of indirection away from the
 		 * actual aliased name.
 		 */
-		target_node = (struct acpi_namespace_node *) target_node->object;
+		target_node = ACPI_CAST_PTR (struct acpi_namespace_node, target_node->object);
 	}
 
 	/*
@@ -117,6 +118,17 @@
 		alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node);
 		break;
 
+	case ACPI_TYPE_METHOD:
+
+		/*
+		 * The new alias has the type ALIAS and points to the original
+		 * NS node, not the object itself.  This is because for these
+		 * types, the object can change dynamically via a Store.
+		 */
+		alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS;
+		alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node);
+		break;
+
 	default:
 
 		/* Attach the original source object to the new Alias Node */
@@ -587,27 +599,33 @@
 	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 -Nru a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
--- a/drivers/acpi/executer/exdump.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/executer/exdump.c	Sat Apr  3 19:38:41 2004
@@ -774,6 +774,7 @@
 
 
 	case ACPI_TYPE_LOCAL_ALIAS:
+	case ACPI_TYPE_LOCAL_METHOD_ALIAS:
 	case ACPI_TYPE_LOCAL_EXTRA:
 	case ACPI_TYPE_LOCAL_DATA:
 	default:
diff -Nru a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
--- a/drivers/acpi/executer/exmutex.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/acpi/executer/exmutex.c	Sat Apr  3 19:38:55 2004
@@ -176,15 +176,18 @@
 	/*
 	 * 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 @@
 		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 -Nru a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
--- a/drivers/acpi/executer/exresnte.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/acpi/executer/exresnte.c	Sat Apr  3 19:38:42 2004
@@ -108,10 +108,11 @@
 	ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Entry=%p source_desc=%p [%s]\n",
 		 node, source_desc, acpi_ut_get_type_name (entry_type)));
 
-	if (entry_type == ACPI_TYPE_LOCAL_ALIAS) {
+	if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) ||
+		(entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
 		/* There is always exactly one level of indirection */
 
-		node       = (struct acpi_namespace_node *) node->object;
+		node       = ACPI_CAST_PTR (struct acpi_namespace_node, node->object);
 		source_desc = acpi_ns_get_attached_object (node);
 		entry_type = acpi_ns_get_type ((acpi_handle) node);
 		*object_ptr = node;
diff -Nru a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
--- a/drivers/acpi/executer/exstoren.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/executer/exstoren.c	Sat Apr  3 19:38:41 2004
@@ -138,6 +138,7 @@
 
 
 	case ACPI_TYPE_LOCAL_ALIAS:
+	case ACPI_TYPE_LOCAL_METHOD_ALIAS:
 
 		/*
 		 * Aliases are resolved by acpi_ex_prep_operands
diff -Nru a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
--- a/drivers/acpi/hardware/hwgpe.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/acpi/hardware/hwgpe.c	Sat Apr  3 19:38:40 2004
@@ -53,9 +53,9 @@
  *
  * FUNCTION:    acpi_hw_enable_gpe
  *
- * PARAMETERS:  gpe_number      - The GPE
+ * PARAMETERS:  gpe_event_info      - Info block for the GPE to be enabled
  *
- * RETURN:      None
+ * RETURN:      Status
  *
  * DESCRIPTION: Enable a single GPE.
  *
@@ -95,7 +95,7 @@
  *
  * FUNCTION:    acpi_hw_enable_gpe_for_wakeup
  *
- * PARAMETERS:  gpe_number      - The GPE
+ * PARAMETERS:  gpe_event_info      - Info block for the GPE to be enabled
  *
  * RETURN:      None
  *
@@ -122,9 +122,11 @@
 	}
 
 	/*
-	 * Set the bit so we will not disable this when sleeping
+	 * Set the bit so we will not enable this GPE when sleeping (and disable
+	 * it upon wake)
 	 */
 	gpe_register_info->wake_enable |= gpe_event_info->bit_mask;
+	gpe_event_info->flags |= (ACPI_GPE_TYPE_WAKE | ACPI_GPE_ENABLED);
 }
 
 
@@ -132,9 +134,9 @@
  *
  * FUNCTION:    acpi_hw_disable_gpe
  *
- * PARAMETERS:  gpe_number      - The GPE
+ * PARAMETERS:  gpe_event_info      - Info block for the GPE to be disabled
  *
- * RETURN:      None
+ * RETURN:      Status
  *
  * DESCRIPTION: Disable a single GPE.
  *
@@ -177,6 +179,8 @@
 		return (status);
 	}
 
+	/* Make sure this GPE is disabled for wake, also */
+
 	acpi_hw_disable_gpe_for_wakeup (gpe_event_info);
 	return (AE_OK);
 }
@@ -186,7 +190,7 @@
  *
  * FUNCTION:    acpi_hw_disable_gpe_for_wakeup
  *
- * PARAMETERS:  gpe_number      - The GPE
+ * PARAMETERS:  gpe_event_info      - Info block for the GPE to be disabled
  *
  * RETURN:      None
  *
@@ -212,9 +216,8 @@
 		return;
 	}
 
-	/*
-	 * Clear the bit so we will disable this when sleeping
-	 */
+	/* Clear the bit so we will disable this when sleeping */
+
 	gpe_register_info->wake_enable &= ~(gpe_event_info->bit_mask);
 }
 
@@ -223,11 +226,11 @@
  *
  * FUNCTION:    acpi_hw_clear_gpe
  *
- * PARAMETERS:  gpe_number      - The GPE
+ * PARAMETERS:  gpe_event_info      - Info block for the GPE to be cleared
  *
- * RETURN:      None
+ * RETURN:      status_status
  *
- * DESCRIPTION: Clear a single GPE.
+ * DESCRIPTION: Clear the status bit for a single GPE.
  *
  ******************************************************************************/
 
@@ -256,9 +259,10 @@
  *
  * FUNCTION:    acpi_hw_get_gpe_status
  *
- * PARAMETERS:  gpe_number      - The GPE
+ * PARAMETERS:  gpe_event_info      - Info block for the GPE to queried
+ *              event_status        - Where the GPE status is returned
  *
- * RETURN:      None
+ * RETURN:      Status
  *
  * DESCRIPTION: Return the status of a single GPE.
  *
@@ -376,7 +380,7 @@
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Clear all GPEs within a GPE block
+ * DESCRIPTION: Clear status bits for all GPEs within a GPE block
  *
  ******************************************************************************/
 
@@ -392,7 +396,7 @@
 	/* Examine each GPE Register within the block */
 
 	for (i = 0; i < gpe_block->register_count; i++) {
-		/* Clear all GPEs in this register */
+		/* Clear status on all GPEs in this register */
 
 		status = acpi_hw_low_level_write (8, 0xFF,
 				 &gpe_block->register_info[i].status_address);
@@ -407,19 +411,20 @@
 
 /******************************************************************************
  *
- * FUNCTION:    acpi_hw_disable_non_wakeup_gpe_block
+ * FUNCTION:    acpi_hw_prepare_gpe_block_for_sleep
  *
  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
  *              gpe_block           - Gpe Block info
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Disable all GPEs except wakeup GPEs in a GPE block
+ * DESCRIPTION: Disable all runtime GPEs and enable all wakeup GPEs -- within
+ *              a single GPE block
  *
  ******************************************************************************/
 
 static acpi_status
-acpi_hw_disable_non_wakeup_gpe_block (
+acpi_hw_prepare_gpe_block_for_sleep (
 	struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
 	struct acpi_gpe_block_info      *gpe_block)
 {
@@ -437,8 +442,11 @@
 
 	for (i = 0; i < gpe_block->register_count; i++) {
 		/*
-		 * Read the enabled status of all GPEs. We
+		 * Read the enabled/disabled status of all GPEs. We
 		 * will be using it to restore all the GPEs later.
+		 *
+		 * NOTE:  Wake GPEs are are ALL disabled at this time, so when we wake
+		 * and restore this register, they will be automatically disabled.
 		 */
 		status = acpi_hw_low_level_read (8, &in_value,
 				 &gpe_register_info->enable_address);
@@ -449,7 +457,8 @@
 		gpe_register_info->enable = (u8) in_value;
 
 		/*
-		 * Disable all GPEs except wakeup GPEs.
+		 * 1) Disable all runtime GPEs
+		 * 2) Enable all wakeup GPEs
 		 */
 		status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable,
 				&gpe_register_info->enable_address);
@@ -457,6 +466,8 @@
 			return (status);
 		}
 
+		/* Point to next GPE register */
+
 		gpe_register_info++;
 	}
 
@@ -466,22 +477,22 @@
 
 /******************************************************************************
  *
- * FUNCTION:    acpi_hw_disable_non_wakeup_gpes
+ * FUNCTION:    acpi_hw_prepare_gpes_for_sleep
  *
  * PARAMETERS:  None
  *
- * RETURN:      None
+ * RETURN:      Status
  *
- * DESCRIPTION: Disable all non-wakeup GPEs
+ * DESCRIPTION: Disable all runtime GPEs, enable all wake GPEs.
  *              Called with interrupts disabled. The interrupt handler also
  *              modifies gpe_register_info->Enable, so it should not be
- *              given the chance to run until after non-wake GPEs are
+ *              given the chance to run until after the runtime GPEs are
  *              re-enabled.
  *
  ******************************************************************************/
 
 acpi_status
-acpi_hw_disable_non_wakeup_gpes (
+acpi_hw_prepare_gpes_for_sleep (
 	void)
 {
 	acpi_status                     status;
@@ -490,27 +501,27 @@
 	ACPI_FUNCTION_ENTRY ();
 
 
-	status = acpi_ev_walk_gpe_list (acpi_hw_disable_non_wakeup_gpe_block);
-
+	status = acpi_ev_walk_gpe_list (acpi_hw_prepare_gpe_block_for_sleep);
 	return (status);
 }
 
 
 /******************************************************************************
  *
- * FUNCTION:    acpi_hw_enable_non_wakeup_gpe_block
+ * FUNCTION:    acpi_hw_restore_gpe_block_on_wake
  *
  * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info
  *              gpe_block           - Gpe Block info
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Enable a single GPE.
+ * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in one
+ *              GPE block
  *
  ******************************************************************************/
 
 static acpi_status
-acpi_hw_enable_non_wakeup_gpe_block (
+acpi_hw_restore_gpe_block_on_wake (
 	struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
 	struct acpi_gpe_block_info      *gpe_block)
 {
@@ -537,8 +548,12 @@
 		}
 
 		/*
-		 * We previously stored the enabled status of all GPEs.
-		 * Blast them back in.
+		 * Restore the GPE Enable register, which will do the following:
+		 *
+		 * 1) Disable all wakeup GPEs
+		 * 2) Enable all runtime GPEs
+		 *
+		 *  (On sleep, we saved the enabled status of all GPEs)
 		 */
 		status = acpi_hw_low_level_write (8, gpe_register_info->enable,
 				 &gpe_register_info->enable_address);
@@ -546,28 +561,30 @@
 			return (status);
 		}
 
+		/* Point to next GPE register */
+
 		gpe_register_info++;
 	}
 
-
 	return (AE_OK);
 }
 
 
 /******************************************************************************
  *
- * FUNCTION:    acpi_hw_enable_non_wakeup_gpes
+ * FUNCTION:    acpi_hw_restore_gpes_on_wake
  *
  * PARAMETERS:  None
  *
- * RETURN:      None
+ * RETURN:      Status
  *
- * DESCRIPTION: Enable all non-wakeup GPEs we previously enabled.
+ * DESCRIPTION: Enable all runtime GPEs and disable all wake GPEs -- in all
+ *              GPE blocks
  *
  ******************************************************************************/
 
 acpi_status
-acpi_hw_enable_non_wakeup_gpes (
+acpi_hw_restore_gpes_on_wake (
 	void)
 {
 	acpi_status                     status;
@@ -576,7 +593,6 @@
 	ACPI_FUNCTION_ENTRY ();
 
 
-	status = acpi_ev_walk_gpe_list (acpi_hw_enable_non_wakeup_gpe_block);
-
+	status = acpi_ev_walk_gpe_list (acpi_hw_restore_gpe_block_on_wake);
 	return (status);
 }
diff -Nru a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
--- a/drivers/acpi/hardware/hwsleep.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/hardware/hwsleep.c	Sat Apr  3 19:38:41 2004
@@ -286,7 +286,11 @@
 		}
 	}
 
-	status = acpi_hw_disable_non_wakeup_gpes ();
+	/*
+	 * 1) Disable all runtime GPEs
+	 * 2) Enable all wakeup GPEs
+	 */
+	status = acpi_hw_prepare_gpes_for_sleep ();
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
@@ -394,7 +398,7 @@
  *
  ******************************************************************************/
 
-acpi_status
+acpi_status asmlinkage
 acpi_enter_sleep_state_s4bios (
 	void)
 {
@@ -415,7 +419,11 @@
 		return_ACPI_STATUS (status);
 	}
 
-	status = acpi_hw_disable_non_wakeup_gpes ();
+	/*
+	 * 1) Disable all runtime GPEs
+	 * 2) Enable all wakeup GPEs
+	 */
+	status = acpi_hw_prepare_gpes_for_sleep ();
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
@@ -528,10 +536,14 @@
 	if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
 		ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status)));
 	}
+	/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
 
-	/* _WAK returns stuff - do we want to look at it? */
-
-	status = acpi_hw_enable_non_wakeup_gpes ();
+	/*
+	 * Restore the GPEs:
+	 * 1) Disable all wakeup GPEs
+	 * 2) Enable all runtime GPEs
+	 */
+	status = acpi_hw_restore_gpes_on_wake ();
 	if (ACPI_FAILURE (status)) {
 		return_ACPI_STATUS (status);
 	}
diff -Nru a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
--- a/drivers/acpi/namespace/nsaccess.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/acpi/namespace/nsaccess.c	Sat Apr  3 19:38:56 2004
@@ -105,8 +105,15 @@
 		"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 @@
 		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 @@
 			 */
 			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 @@
 			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 @@
 
 
 			default:
+
 				ACPI_REPORT_ERROR (("Unsupported initial type value %X\n",
 					init_val->type));
 				acpi_ut_remove_reference (obj_desc);
@@ -233,6 +247,14 @@
 
 unlock_and_exit:
 	(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+
+	/* Save a handle to "_GPE", it is always present */
+
+	if (ACPI_SUCCESS (status)) {
+		status = acpi_ns_get_node_by_path ("\\_GPE", NULL, ACPI_NS_NO_UPSEARCH,
+				  &acpi_gbl_fadt_gpe_device);
+	}
+
 	return_ACPI_STATUS (status);
 }
 
@@ -563,6 +585,7 @@
 		if ((num_segments       == 0)                               &&
 			(type_to_check_for  != ACPI_TYPE_ANY)                   &&
 			(type_to_check_for  != ACPI_TYPE_LOCAL_ALIAS)           &&
+			(type_to_check_for  != ACPI_TYPE_LOCAL_METHOD_ALIAS)    &&
 			(type_to_check_for  != ACPI_TYPE_LOCAL_SCOPE)           &&
 			(this_node->type    != ACPI_TYPE_ANY)                   &&
 			(this_node->type    != type_to_check_for)) {
diff -Nru a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
--- a/drivers/acpi/namespace/nsalloc.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/namespace/nsalloc.c	Sat Apr  3 19:38:43 2004
@@ -334,10 +334,11 @@
 	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 -Nru a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
--- a/drivers/acpi/namespace/nsdump.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/acpi/namespace/nsdump.c	Sat Apr  3 19:38:55 2004
@@ -351,6 +351,7 @@
 
 
 		case ACPI_TYPE_LOCAL_ALIAS:
+		case ACPI_TYPE_LOCAL_METHOD_ALIAS:
 
 			acpi_os_printf ("Target %4.4s (%p)\n", acpi_ut_get_node_name (obj_desc), obj_desc);
 			break;
diff -Nru a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
--- a/drivers/acpi/namespace/nseval.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/namespace/nseval.c	Sat Apr  3 19:38:43 2004
@@ -82,11 +82,11 @@
 	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 @@
 		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 @@
 
 	/* 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 @@
 		pathname));
 
 cleanup:
+	acpi_ut_delete_generic_state (scope_info);
 
+cleanup1:
 	ACPI_MEM_FREE (internal_path);
 	return_ACPI_STATUS (status);
 }
@@ -301,6 +308,15 @@
 	if (!node) {
 		(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
 		return_ACPI_STATUS (AE_BAD_PARAMETER);
+	}
+
+	/*
+	 * For a method alias, we must grab the actual method node
+	 * so that proper scoping context will be established
+	 * before execution.
+	 */
+	if (acpi_ns_get_type (node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+		node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object);
 	}
 
 	/*
diff -Nru a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
--- a/drivers/acpi/namespace/nssearch.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/acpi/namespace/nssearch.c	Sat Apr  3 19:38:56 2004
@@ -113,6 +113,12 @@
 		/* Check for match against the name */
 
 		if (next_node->name.integer == target_name) {
+			/* Resolve a control method alias if any */
+
+			if (acpi_ns_get_type (next_node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+				next_node = ACPI_CAST_PTR (struct acpi_namespace_node, next_node->object);
+			}
+
 			/*
 			 * Found matching entry.
 			 */
diff -Nru a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
--- a/drivers/acpi/namespace/nsutils.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/namespace/nsutils.c	Sat Apr  3 19:38:43 2004
@@ -256,7 +256,7 @@
 
 
 	if (!node) {
-		ACPI_REPORT_WARNING (("ns_get_type: Null Node ptr"));
+		ACPI_REPORT_WARNING (("ns_get_type: Null Node input pointer\n"));
 		return_VALUE (ACPI_TYPE_ANY);
 	}
 
diff -Nru a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
--- a/drivers/acpi/namespace/nsxfeval.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/acpi/namespace/nsxfeval.c	Sat Apr  3 19:38:56 2004
@@ -45,6 +45,7 @@
 
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
 
 
 #define _COMPONENT          ACPI_NAMESPACE
@@ -149,11 +150,11 @@
  * FUNCTION:    acpi_evaluate_object
  *
  * PARAMETERS:  Handle              - Object handle (optional)
- *              *Pathname           - Object pathname (optional)
- *              **external_params   - List of parameters to pass to method,
+ *              Pathname            - Object pathname (optional)
+ *              external_params     - List of parameters to pass to method,
  *                                    terminated by NULL.  May be NULL
  *                                    if no parameters are being passed.
- *              *return_buffer      - Where to put method's return value (if
+ *              return_buffer       - Where to put method's return value (if
  *                                    any).  If NULL, no value is returned.
  *
  * RETURN:      Status
@@ -172,6 +173,7 @@
 	struct acpi_buffer              *return_buffer)
 {
 	acpi_status                     status;
+	acpi_status                     status2;
 	union acpi_operand_object       **internal_params = NULL;
 	union acpi_operand_object       *internal_return_obj = NULL;
 	acpi_size                       buffer_space_needed;
@@ -203,7 +205,7 @@
 		 */
 		for (i = 0; i < external_params->count; i++) {
 			status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i],
-					 &internal_params[i]);
+					  &internal_params[i]);
 			if (ACPI_FAILURE (status)) {
 				acpi_ut_delete_internal_object_list (internal_params);
 				return_ACPI_STATUS (status);
@@ -321,14 +323,20 @@
 		}
 	}
 
-	/* Delete the return and parameter objects */
-
 	if (internal_return_obj) {
 		/*
-		 * Delete the internal return object. (Or at least
-		 * decrement the reference count by one)
+		 * Delete the internal return object.  NOTE: Interpreter
+		 * must be locked to avoid race condition.
 		 */
-		acpi_ut_remove_reference (internal_return_obj);
+		status2 = acpi_ex_enter_interpreter ();
+		if (ACPI_SUCCESS (status2)) {
+			/*
+			 * Delete the internal return object. (Or at least
+			 * decrement the reference count by one)
+			 */
+			acpi_ut_remove_reference (internal_return_obj);
+			acpi_ex_exit_interpreter ();
+		}
 	}
 
 	/*
diff -Nru a/drivers/acpi/numa.c b/drivers/acpi/numa.c
--- a/drivers/acpi/numa.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/acpi/numa.c	Sat Apr  3 19:38:54 2004
@@ -32,12 +32,19 @@
 #include <acpi/acpi_bus.h>
 #include <acpi/acmacros.h>
 
+#define ACPI_NUMA	0x80000000
+#define _COMPONENT	ACPI_NUMA
+	ACPI_MODULE_NAME ("numa")
+
 extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, unsigned int max_entries);
 
 void __init
 acpi_table_print_srat_entry (
 	acpi_table_entry_header	*header)
 {
+
+	ACPI_FUNCTION_NAME ("acpi_table_print_srat_entry");
+
 	if (!header)
 		return;
 
@@ -47,7 +54,7 @@
 	{
 		struct acpi_table_processor_affinity *p =
 			(struct acpi_table_processor_affinity*) header;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
 		       p->apic_id, p->lsapic_eid, p->proximity_domain,
 		       p->flags.enabled?"enabled":"disabled"));
 	}
@@ -57,7 +64,7 @@
 	{
 		struct acpi_table_memory_affinity *p =
 			(struct acpi_table_memory_affinity*) header;
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
 		       p->base_addr_hi, p->base_addr_lo, p->length_hi, p->length_lo,
 		       p->memory_type, p->proximity_domain,
 		       p->flags.enabled ? "enabled" : "disabled",
diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c
--- a/drivers/acpi/osl.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/acpi/osl.c	Sat Apr  3 19:38:55 2004
@@ -1012,3 +1012,60 @@
 }
 
 __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);
+
+/*
+ * Wake and Run-Time GPES are expected to be separate.
+ * We disable wake-GPEs at run-time to prevent spurious
+ * interrupts.
+ *
+ * However, if a system exists that shares Wake and
+ * Run-time events on the same GPE this flag is available
+ * to tell Linux to keep the wake-time GPEs enabled at run-time.
+ */
+static int __init
+acpi_leave_gpes_disabled_setup(char *str)
+{
+	printk(KERN_INFO PREFIX "leave wake GPEs disabled\n");
+
+	acpi_gbl_leave_wake_gpes_disabled = TRUE;
+
+	return 1;
+}
+
+__setup("acpi_leave_gpes_disabled", acpi_leave_gpes_disabled_setup);
+
diff -Nru a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
--- a/drivers/acpi/parser/psparse.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/parser/psparse.c	Sat Apr  3 19:38:41 2004
@@ -426,7 +426,7 @@
 	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 @@
 			/* 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 @@
 						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 @@
 					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 @@
 
 		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 @@
 		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 -Nru a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
--- a/drivers/acpi/parser/psscope.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/parser/psscope.c	Sat Apr  3 19:38:41 2004
@@ -167,7 +167,6 @@
 		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_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_ut_delete_generic_state (scope);
 	}
-
 	else {
 		/* empty parse stack, prepare to fetch next opcode */
 
@@ -250,7 +246,6 @@
 		*arg_count              = 0;
 	}
 
-
 	ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped Op %p Args %X\n", *op, *arg_count));
 	return_VOID;
 }
@@ -275,13 +270,13 @@
 {
 	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 */
 
diff -Nru a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
--- a/drivers/acpi/pci_irq.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/pci_irq.c	Sat Apr  3 19:38:43 2004
@@ -273,7 +273,6 @@
 	return_VALUE(entry->irq);
 }
 
-
 static int
 acpi_pci_irq_derive (
 	struct pci_dev		*dev,
@@ -281,6 +280,7 @@
 {
 	struct pci_dev		*bridge = dev;
 	int			irq = 0;
+	u8			bridge_pin = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_pci_irq_derive");
 
@@ -289,11 +289,25 @@
 
 	/* 
 	 * Attempt to derive an IRQ for this device from a parent bridge's
-	 * PCI interrupt routing entry (a.k.a. the "bridge swizzle").
+	 * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge).
 	 */
 	while (!irq && bridge->bus->self) {
 		pin = (pin + PCI_SLOT(bridge->devfn)) % 4;
 		bridge = bridge->bus->self;
+
+		if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
+			/* PC card has the same IRQ as its cardbridge */
+			pci_read_config_byte(bridge, PCI_INTERRUPT_PIN, &bridge_pin);
+			if (!bridge_pin) {
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO, 
+					"No interrupt pin configured for device %s\n", pci_name(bridge)));
+				return_VALUE(0);
+			}
+			/* Pin is from 0 to 3 */
+			bridge_pin --;
+			pin = bridge_pin;
+		}
+
 		irq = acpi_pci_irq_lookup(bridge->bus,
 				PCI_SLOT(bridge->devfn), pin);
 	}
@@ -303,7 +317,8 @@
 		return_VALUE(0);
 	}
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derived IRQ %d\n", irq));
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n",
+		irq, pci_name(dev), pci_name(bridge)));
 
 	return_VALUE(irq);
 }
@@ -338,7 +353,7 @@
 	 * values override any BIOS-assigned IRQs set during boot.
 	 */
  	irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin);
- 
+
 	/*
 	 * If no PRT entry was found, we'll try to derive an IRQ from the
 	 * device's parent bridge.
diff -Nru a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
--- a/drivers/acpi/pci_link.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/pci_link.c	Sat Apr  3 19:38:41 2004
@@ -72,6 +72,7 @@
 	u8			edge_level;		/* All IRQs */
 	u8			active_high_low;	/* All IRQs */
 	u8			setonboot;
+	u8			resource_type;
 	u8			possible_count;
 	u8			possible[ACPI_PCI_LINK_MAX_POSSIBLE];
 };
@@ -123,6 +124,7 @@
 		}
 		link->irq.edge_level = p->edge_level;
 		link->irq.active_high_low = p->active_high_low;
+		link->irq.resource_type = ACPI_RSTYPE_IRQ;
 		break;
 	}
 	case ACPI_RSTYPE_EXT_IRQ:
@@ -143,6 +145,7 @@
 		}
 		link->irq.edge_level = p->edge_level;
 		link->irq.active_high_low = p->active_high_low;
+		link->irq.resource_type = ACPI_RSTYPE_EXT_IRQ;
 		break;
 	}
 	default:
@@ -342,13 +345,18 @@
 		}
 	}
 
+	resource_type = link->irq.resource_type;
+
+	if (resource_type != ACPI_RSTYPE_IRQ &&
+			resource_type != ACPI_RSTYPE_EXT_IRQ){
 	/* If IRQ<=15, first try with a "normal" IRQ descriptor. If that fails, try with
 	 * an extended one */
-	if (irq <= 15) {
-		resource_type = ACPI_RSTYPE_IRQ;
-	} else {
-		resource_type = ACPI_RSTYPE_EXT_IRQ;
-	}
+		if (irq <= 15) {
+			resource_type = ACPI_RSTYPE_IRQ;
+		} else {
+			resource_type = ACPI_RSTYPE_EXT_IRQ;
+		}
+	} 
 
 retry_programming:
    
diff -Nru a/drivers/acpi/power.c b/drivers/acpi/power.c
--- a/drivers/acpi/power.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/power.c	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c
--- a/drivers/acpi/processor.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/acpi/processor.c	Sat Apr  3 19:38:45 2004
@@ -67,8 +67,6 @@
 #define C3_OVERHEAD			4	/* 1us (3.579 ticks per us) */
 
 
-const u32 POWER_OF_2[] = {1,2,4,8,16,32,64};
-
 #define ACPI_PROCESSOR_LIMIT_USER	0
 #define ACPI_PROCESSOR_LIMIT_THERMAL	1
 
@@ -1489,7 +1487,7 @@
 		return_VALUE(0);
 	}
 
-	pr->throttling.state_count = POWER_OF_2[acpi_fadt.duty_width];
+	pr->throttling.state_count = 1 << acpi_fadt.duty_width;
 
 	/*
 	 * Compute state values. Note that throttling displays a linear power/
diff -Nru a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
--- a/drivers/acpi/resources/rsaddr.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/resources/rsaddr.c	Sat Apr  3 19:38:43 2004
@@ -88,6 +88,7 @@
 
 	ACPI_FUNCTION_TRACE ("rs_address16_resource");
 
+
 	/*
 	 * Point past the Descriptor to get the number of bytes consumed
 	 */
@@ -149,7 +150,7 @@
 		output_struct->data.address16.attribute.memory.read_write_attribute =
 				(u16) (temp8 & 0x01);
 		output_struct->data.address16.attribute.memory.cache_attribute =
-				(u16) ((temp8 >> 1) & 0x0F);
+				(u16) ((temp8 >> 1) & 0x03);
 	}
 	else {
 		if (ACPI_IO_RANGE == output_struct->data.address16.resource_type) {
@@ -347,7 +348,7 @@
 
 		temp8 |=
 			(linked_list->data.address16.attribute.memory.cache_attribute &
-			 0x0F) << 1;
+			 0x03) << 1;
 	}
 	else if (ACPI_IO_RANGE == linked_list->data.address16.resource_type) {
 		temp8 = (u8)
@@ -539,7 +540,7 @@
 				(u16) (temp8 & 0x01);
 
 		output_struct->data.address32.attribute.memory.cache_attribute =
-				(u16) ((temp8 >> 1) & 0x0F);
+				(u16) ((temp8 >> 1) & 0x03);
 	}
 	else {
 		if (ACPI_IO_RANGE == output_struct->data.address32.resource_type) {
@@ -735,7 +736,7 @@
 
 		temp8 |=
 			(linked_list->data.address32.attribute.memory.cache_attribute &
-			 0x0F) << 1;
+			 0x03) << 1;
 	}
 	else if (ACPI_IO_RANGE == linked_list->data.address32.resource_type) {
 		temp8 = (u8)
@@ -926,7 +927,7 @@
 				(u16) (temp8 & 0x01);
 
 		output_struct->data.address64.attribute.memory.cache_attribute =
-				(u16) ((temp8 >> 1) & 0x0F);
+				(u16) ((temp8 >> 1) & 0x03);
 	}
 	else {
 		if (ACPI_IO_RANGE == output_struct->data.address64.resource_type) {
@@ -1124,7 +1125,7 @@
 
 		temp8 |=
 			(linked_list->data.address64.attribute.memory.cache_attribute &
-			 0x0F) << 1;
+			 0x03) << 1;
 	}
 	else if (ACPI_IO_RANGE == linked_list->data.address64.resource_type) {
 		temp8 = (u8)
diff -Nru a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
--- a/drivers/acpi/sleep/poweroff.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/acpi/sleep/poweroff.c	Sat Apr  3 19:38:56 2004
@@ -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 -Nru a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
--- a/drivers/acpi/sleep/proc.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/acpi/sleep/proc.c	Sat Apr  3 19:38:45 2004
@@ -99,7 +99,7 @@
 	if (acpi_gbl_FADT->mon_alrm)
 		mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
 	else
-		mo = CMOS_READ(RTC_MONTH);;
+		mo = CMOS_READ(RTC_MONTH);
 	if (acpi_gbl_FADT->century)
 		yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
 	else
diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c
--- a/drivers/acpi/tables.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/acpi/tables.c	Sat Apr  3 19:38:43 2004
@@ -386,8 +386,13 @@
 	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 -Nru a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
--- a/drivers/acpi/toshiba_acpi.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/toshiba_acpi.c	Sat Apr  3 19:38:41 2004
@@ -33,7 +33,7 @@
  *
  */
 
-#define TOSHIBA_ACPI_VERSION	"0.17"
+#define TOSHIBA_ACPI_VERSION	"0.18"
 #define PROC_INTERFACE_VERSION	1
 
 #include <linux/kernel.h>
@@ -41,6 +41,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
+#include <asm/uaccess.h>
 
 #include <acpi/acpi_drivers.h>
 
@@ -105,24 +106,6 @@
 	*word = (*word & ~mask) | (mask * value);
 }
 
-/* an sscanf that takes explicit string length */
-static int
-snscanf(const char* str, int n, const char* format, ...)
-{
-	va_list args;
-	int result;
-	char* str2 = kmalloc(n + 1, GFP_KERNEL);
-	if (str2 == 0) return 0;
-	/* NOTE: don't even _think_ about replacing this with strlcpy */
-	strncpy(str2, str, n);
-	str2[n] = 0;
-	va_start(args, format);
-	result = vsscanf(str2, format, args);
-	va_end(args);
-	kfree(str2);
-	return result;
-}
-
 /* acpi interface wrappers
  */
 
@@ -269,10 +252,26 @@
 }
 
 static int
-dispatch_write(struct file* file, const char* buffer, unsigned long count,
-	ProcItem* item)
+dispatch_write(struct file* file, __user const char* buffer,
+	unsigned long count, ProcItem* item)
 {
-	return item->write_func(buffer, count);
+	int result;
+	char* tmp_buffer;
+
+	/* Arg buffer points to userspace memory, which can't be accessed
+	 * directly.  Since we're making a copy, zero-terminate the
+	 * destination so that sscanf can be used on it safely.
+	 */
+	tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
+	if (copy_from_user(tmp_buffer, buffer, count)) {
+		result = -EFAULT;
+	}
+	else {
+		tmp_buffer[count] = 0;
+		result = item->write_func(tmp_buffer, count);
+	}
+	kfree(tmp_buffer);
+	return result;
 }
 
 static char*
@@ -300,7 +299,7 @@
 	int value;
 	u32 hci_result;
 
-	if (snscanf(buffer, count, " brightness : %i", &value) == 1 &&
+	if (sscanf(buffer, " brightness : %i", &value) == 1 &&
 			value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
 		value = value << HCI_LCD_BRIGHTNESS_SHIFT;
 		hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
@@ -350,11 +349,11 @@
 	 *  NOTE: to keep scanning simple, invalid fields are ignored
 	 */
 	while (remain) {
-		if (snscanf(buffer, remain, " lcd_out : %i", &value) == 1)
+		if (sscanf(buffer, " lcd_out : %i", &value) == 1)
 			lcd_out = value & 1;
-		else if (snscanf(buffer, remain, " crt_out : %i", &value) == 1)
+		else if (sscanf(buffer, " crt_out : %i", &value) == 1)
 			crt_out = value & 1;
-		else if (snscanf(buffer, remain, " tv_out : %i", &value) == 1)
+		else if (sscanf(buffer, " tv_out : %i", &value) == 1)
 			tv_out = value & 1;
 		/* advance to one character past the next ; */
 		do {
@@ -407,7 +406,7 @@
 	int value;
 	u32 hci_result;
 
-	if (snscanf(buffer, count, " force_on : %i", &value) == 1 &&
+	if (sscanf(buffer, " force_on : %i", &value) == 1 &&
 			value >= 0 && value <= 1) {
 		hci_write1(HCI_FAN, value, &hci_result);
 		if (hci_result != HCI_SUCCESS)
@@ -458,7 +457,7 @@
 {
 	int value;
 
-	if (snscanf(buffer, count, " hotkey_ready : %i", &value) == 1 &&
+	if (sscanf(buffer, " hotkey_ready : %i", &value) == 1 &&
 			value == 0) {
 		key_event_valid = 0;
 	} else {
diff -Nru a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
--- a/drivers/acpi/utilities/uteval.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/utilities/uteval.c	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
--- a/drivers/acpi/utilities/utglobal.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/utilities/utglobal.c	Sat Apr  3 19:38:41 2004
@@ -185,6 +185,15 @@
 					   "_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 @@
 /*
  * 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 @@
 	{"_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 @@
  * 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              */
@@ -249,14 +253,15 @@
 	ACPI_NS_NORMAL,                     /* 19 index_field      */
 	ACPI_NS_NORMAL,                     /* 20 Reference        */
 	ACPI_NS_NORMAL,                     /* 21 Alias            */
-	ACPI_NS_NORMAL,                     /* 22 Notify           */
-	ACPI_NS_NORMAL,                     /* 23 Address Handler  */
-	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 24 Resource Desc    */
-	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 25 Resource Field   */
-	ACPI_NS_NEWSCOPE,                   /* 26 Scope            */
-	ACPI_NS_NORMAL,                     /* 27 Extra            */
-	ACPI_NS_NORMAL,                     /* 28 Data             */
-	ACPI_NS_NORMAL                      /* 29 Invalid          */
+	ACPI_NS_NORMAL,                     /* 22 method_alias     */
+	ACPI_NS_NORMAL,                     /* 23 Notify           */
+	ACPI_NS_NORMAL,                     /* 24 Address Handler  */
+	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 25 Resource Desc    */
+	ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL,   /* 26 Resource Field   */
+	ACPI_NS_NEWSCOPE,                   /* 27 Scope            */
+	ACPI_NS_NORMAL,                     /* 28 Extra            */
+	ACPI_NS_NORMAL,                     /* 29 Data             */
+	ACPI_NS_NORMAL                      /* 30 Invalid          */
 };
 
 
@@ -303,10 +308,8 @@
  *
  ******************************************************************************/
 
-
 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 +473,8 @@
  *
  * 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 */
 
@@ -500,14 +502,15 @@
 	/* 19 */ "index_field",
 	/* 20 */ "Reference",
 	/* 21 */ "Alias",
-	/* 22 */ "Notify",
-	/* 23 */ "addr_handler",
-	/* 24 */ "resource_desc",
-	/* 25 */ "resource_fld",
-	/* 26 */ "Scope",
-	/* 27 */ "Extra",
-	/* 28 */ "Data",
-	/* 39 */ "Invalid"
+	/* 22 */ "method_alias",
+	/* 23 */ "Notify",
+	/* 24 */ "addr_handler",
+	/* 25 */ "resource_desc",
+	/* 26 */ "resource_fld",
+	/* 27 */ "Scope",
+	/* 28 */ "Extra",
+	/* 29 */ "Data",
+	/* 30 */ "Invalid"
 };
 
 
@@ -555,7 +558,7 @@
 acpi_ut_get_node_name (
 	void                            *object)
 {
-	struct acpi_namespace_node      *node;
+	struct acpi_namespace_node      *node = (struct acpi_namespace_node *) object;
 
 
 	if (!object)
@@ -563,7 +566,10 @@
 		return ("NULL NODE");
 	}
 
-	node = (struct acpi_namespace_node *) object;
+	if (object == ACPI_ROOT_OBJECT)
+	{
+		node = acpi_gbl_root_node;
+	}
 
 	if (node->descriptor != ACPI_DESC_TYPE_NAMED)
 	{
@@ -776,6 +782,11 @@
 
 
 	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 */
 
diff -Nru a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
--- a/drivers/acpi/utilities/utmisc.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/acpi/utilities/utmisc.c	Sat Apr  3 19:38:41 2004
@@ -529,6 +529,7 @@
 	return (src_string);
 }
 
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_mutex_initialize
@@ -562,10 +563,8 @@
 		}
 	}
 
-
 	status = acpi_os_create_lock (&acpi_gbl_gpe_lock);
-
-	return_ACPI_STATUS (AE_OK);
+	return_ACPI_STATUS (status);
 }
 
 
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/atm/fore200e.c	Sat Apr  3 19:38:56 2004
@@ -482,11 +482,19 @@
 
 
 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 @@
 
 
 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 @@
 	/* 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 @@
 
     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 @@
       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 @@
       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 -Nru a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
--- a/drivers/atm/fore200e.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/atm/fore200e.h	Sat Apr  3 19:38:43 2004
@@ -801,7 +801,8 @@
     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 -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/atm/idt77252.c	Sat Apr  3 19:38:43 2004
@@ -1064,8 +1064,8 @@
 
 	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)) {
@@ -1902,6 +1902,9 @@
 {
 	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) {
diff -Nru a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
--- a/drivers/atm/nicstar.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/atm/nicstar.c	Sat Apr  3 19:38:42 2004
@@ -112,9 +112,6 @@
 
 /* Macros *********************************************************************/
 
-#define MAX(a,b) ((a) > (b) ? (a) : (b))
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-
 #define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ)
 
 #define NS_DELAY mdelay(1)
@@ -2483,7 +2480,7 @@
             for (j = 1; j < NS_SKB(iovb)->iovcnt; j++)
             {
                lb = (struct sk_buff *) iov->iov_base;
-               tocopy = MIN(remaining, iov->iov_len);
+               tocopy = min_t(int, remaining, iov->iov_len);
                memcpy(hb->tail, lb->data, tocopy);
                skb_put(hb, tocopy);
                iov++;
diff -Nru a/drivers/atm/suni.c b/drivers/atm/suni.c
--- a/drivers/atm/suni.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/atm/suni.c	Sat Apr  3 19:38:55 2004
@@ -230,7 +230,7 @@
 	unsigned long flags;
 	int first;
 
-	if (!(dev->dev_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
+	if (!(dev->phy_data = kmalloc(sizeof(struct suni_priv),GFP_KERNEL)))
 		return -ENOMEM;
 
 	PRIV(dev)->dev = dev;
diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile
--- a/drivers/base/Makefile	Sat Apr  3 19:38:55 2004
+++ b/drivers/base/Makefile	Sat Apr  3 19:38:55 2004
@@ -6,3 +6,8 @@
 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 -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/base/bus.c	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/drivers/base/class.c b/drivers/base/class.c
--- a/drivers/base/class.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/base/class.c	Sat Apr  3 19:38:56 2004
@@ -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 @@
 
 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 -Nru a/drivers/base/class_simple.c b/drivers/base/class_simple.c
--- a/drivers/base/class_simple.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/base/class_simple.c	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/base/core.c	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/drivers/base/cpu.c b/drivers/base/cpu.c
--- a/drivers/base/cpu.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/base/cpu.c	Sat Apr  3 19:38:42 2004
@@ -7,6 +7,7 @@
 #include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/topology.h>
+#include <linux/device.h>
 
 
 struct sysdev_class cpu_sysdev_class = {
@@ -14,6 +15,46 @@
 };
 EXPORT_SYMBOL(cpu_sysdev_class);
 
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t show_online(struct sys_device *dev, char *buf)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+
+	return sprintf(buf, "%u\n", !!cpu_online(cpu->sysdev.id));
+}
+
+static ssize_t store_online(struct sys_device *dev, const char *buf,
+			    size_t count)
+{
+	struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+	ssize_t ret;
+
+	switch (buf[0]) {
+	case '0':
+		ret = cpu_down(cpu->sysdev.id);
+		break;
+	case '1':
+		ret = cpu_up(cpu->sysdev.id);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (ret >= 0)
+		ret = count;
+	return ret;
+}
+static SYSDEV_ATTR(online, 0600, show_online, store_online);
+
+static void __init register_cpu_control(struct cpu *cpu)
+{
+	sysdev_create_file(&cpu->sysdev, &attr_online);
+}
+#else /* ... !CONFIG_HOTPLUG_CPU */
+static inline void register_cpu_control(struct cpu *cpu)
+{
+}
+#endif /* CONFIG_HOTPLUG_CPU */
 
 /*
  * register_cpu - Setup a driverfs device for a CPU.
@@ -34,6 +75,8 @@
 		error = sysfs_create_link(&root->sysdev.kobj,
 					  &cpu->sysdev.kobj,
 					  kobject_name(&cpu->sysdev.kobj));
+	if (!error)
+		register_cpu_control(cpu);
 	return error;
 }
 
diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c
--- a/drivers/base/driver.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/base/driver.c	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/drivers/base/map.c b/drivers/base/map.c
--- a/drivers/base/map.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/base/map.c	Sat Apr  3 19:38:45 2004
@@ -96,7 +96,7 @@
 {
 	struct kobject *kobj;
 	struct probe *p;
-	unsigned best = ~0U;
+	unsigned long best = ~0UL;
 
 retry:
 	down_read(domain->sem);
diff -Nru a/drivers/base/power/Makefile b/drivers/base/power/Makefile
--- a/drivers/base/power/Makefile	Sat Apr  3 19:38:42 2004
+++ b/drivers/base/power/Makefile	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/drivers/base/power/main.c b/drivers/base/power/main.c
--- a/drivers/base/power/main.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/base/power/main.c	Sat Apr  3 19:38:55 2004
@@ -20,10 +20,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_DEBUG_DRIVER
-#define DEBUG	1
-#endif
-
 #include <linux/device.h>
 #include "power.h"
 
diff -Nru a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
--- a/drivers/base/power/shutdown.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/base/power/shutdown.c	Sat Apr  3 19:38:45 2004
@@ -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 -Nru a/drivers/base/sys.c b/drivers/base/sys.c
--- a/drivers/base/sys.c	Sat Apr  3 19:38:31 2004
+++ b/drivers/base/sys.c	Sat Apr  3 19:38:31 2004
@@ -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 -Nru a/drivers/block/Kconfig b/drivers/block/Kconfig
--- a/drivers/block/Kconfig	Sat Apr  3 19:38:42 2004
+++ b/drivers/block/Kconfig	Sat Apr  3 19:38:42 2004
@@ -6,7 +6,7 @@
 
 config BLK_DEV_FD
 	tristate "Normal floppy disk support"
-	depends on (!X86_PC9800 && !ARCH_S390 && !M68K) || Q40 || (SUN3X && BROKEN)
+	depends on (!X86_PC9800 && !ARCH_S390 && !M68K && !IA64) || Q40 || (SUN3X && BROKEN)
 	---help---
 	  If you want to use the floppy disk drive(s) of your PC under Linux,
 	  say Y. Information about this driver, especially important for IBM
@@ -292,6 +292,15 @@
 
 	  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---
@@ -321,7 +330,7 @@
 
 config BLK_DEV_INITRD
 	bool "Initial RAM disk (initrd) support"
-	depends on BLK_DEV_RAM && BLK_DEV_RAM!=m
+	depends on BLK_DEV_RAM=y
 	help
 	  The initial RAM disk is a RAM disk that is loaded by the boot loader
 	  (loadlin or lilo) and that is mounted as root before the normal boot
diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile
--- a/drivers/block/Makefile	Sat Apr  3 19:38:55 2004
+++ b/drivers/block/Makefile	Sat Apr  3 19:38:55 2004
@@ -40,3 +40,5 @@
 obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o
 
 obj-$(CONFIG_VIODASD)		+= viodasd.o
+obj-$(CONFIG_BLK_DEV_CARMEL)	+= carmel.o
+
diff -Nru a/drivers/block/carmel.c b/drivers/block/carmel.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/block/carmel.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,1774 @@
+/*
+ *  carmel.c: Driver for Promise SATA SX8 looks-like-I2O hardware
+ *
+ *  Copyright 2004 Red Hat, Inc.
+ *
+ *  Author/maintainer:  Jeff Garzik <jgarzik@pobox.com>
+ *
+ *  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.
+ */
+
+#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 SATA 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.8"
+#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_NON_RAID		= FW_VER_NON_RAID,
+	FL_4PORT		= FW_VER_4PORT,
+	FL_FW_VER_MASK		= (FW_VER_NON_RAID | FW_VER_4PORT),
+	FL_DAC			= (1 << 16),
+	FL_DYN_MAJOR		= (1 << 17),
+};
+
+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;
+	int				id;
+	char				name[32];
+
+	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 unsigned long carm_major_alloc;
+
+
+
+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,
+	       (unsigned long long) 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", host->id, i);
+		sprintf(disk->devfs_name, DRV_NAME "/%u_%u", 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 (disk->flags & GENHD_FL_UP)
+				del_gendisk(disk);
+			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;
+
+	/*
+	 * Figure out which major to use: 160, 161, or dynamic
+	 */
+	if (!test_and_set_bit(0, &carm_major_alloc))
+		host->major = 160;
+	else if (!test_and_set_bit(1, &carm_major_alloc))
+		host->major = 161;
+	else
+		host->flags |= FL_DYN_MAJOR;
+
+	host->id = carm_host_id;
+	sprintf(host->name, DRV_NAME "%d", carm_host_id);
+
+	rc = register_blkdev(host->major, host->name);
+	if (rc < 0)
+		goto err_out_free_majors;
+	if (host->flags & FL_DYN_MAJOR)
+		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);
+
+	printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n",
+	       host->name, pci_name(pdev), (int) CARM_MAX_PORTS,
+	       pci_resource_start(pdev, 0), pdev->irq, host->major);
+
+	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, host->name);
+err_out_free_majors:
+	if (host->major == 160)
+		clear_bit(0, &carm_major_alloc);
+	else if (host->major == 161)
+		clear_bit(1, &carm_major_alloc);
+	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, host->name);
+	if (host->major == 160)
+		clear_bit(0, &carm_major_alloc);
+	else if (host->major == 161)
+		clear_bit(1, &carm_major_alloc);
+	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);
+	pci_set_drvdata(pdev, NULL);
+}
+
+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 -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/block/cciss.c	Sat Apr  3 19:38:56 2004
@@ -469,11 +469,8 @@
                         driver_geo.heads = drv->heads;
                         driver_geo.sectors = drv->sectors;
                         driver_geo.cylinders = drv->cylinders;
-                } else {
-                        driver_geo.heads = 0xff;
-                        driver_geo.sectors = 0x3f;
-                        driver_geo.cylinders = (int)drv->nr_blocks / (0xff*0x3f);
-                }
+                } else
+			return -ENXIO;
                 driver_geo.start= get_start_sect(inode->i_bdev);
                 if (copy_to_user((void *) arg, &driver_geo,
                                 sizeof( struct hd_geometry)))
diff -Nru a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
--- a/drivers/block/cciss_scsi.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/block/cciss_scsi.c	Sat Apr  3 19:38:42 2004
@@ -693,7 +693,7 @@
 	scsi_cmd_free(ctlr, cp);
 }
 
-static int __init 
+static int
 cciss_scsi_detect(int ctlr)
 {
 	struct Scsi_Host *sh;
@@ -1058,6 +1058,7 @@
 		int devtype;
 
 		/* for each physical lun, do an inquiry */
+		if (ld_buff->LUN[i][3] & 0xC0) continue;
 		memset(inq_buff, 0, sizeof(InquiryData_struct));
 		memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
 
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/block/cpqarray.c	Sat Apr  3 19:38:41 2004
@@ -16,7 +16,7 @@
  *    along with this program; if not, write to the Free Software
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *    Questions/Comments/Bugfixes to arrays@compaq.com
+ *    Questions/Comments/Bugfixes to Cpqarray-discuss@lists.sourceforge.net
  *
  */
 #include <linux/config.h>	/* CONFIG_PROC_FS */
@@ -46,13 +46,13 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.5)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,5)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.6.0)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,6,0)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
 MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers version 2.6.0");
 MODULE_LICENSE("GPL");
 
 #include "cpqarray.h"
@@ -97,6 +97,34 @@
 	{ 0x40580E11, "Smart Array 431",	&smart4_access },
 };
 
+/* define the PCI info for the PCI cards this driver can control */
+const struct pci_device_id cpqarray_pci_device_id[] =
+{
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,
+		0x0E11, 0x4058, 0, 0, 0},       /* SA431 */
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,
+		0x0E11, 0x4051, 0, 0, 0},      /* SA4250ES */
+	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_COMPAQ_42XX,
+		0x0E11, 0x4050, 0, 0, 0},      /* SA4200 */
+	{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C1510,
+		0x0E11, 0x4048, 0, 0, 0},       /* LC2 */
+	{ PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C1510,
+		0x0E11, 0x4040, 0, 0, 0},      /* Integrated Array */
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
+		0x0E11, 0x4034, 0, 0, 0},       /* SA 221 */
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
+		0x0E11, 0x4033, 0, 0, 0},       /* SA 3100ES*/
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
+		0x0E11, 0x4032, 0, 0, 0},       /* SA 3200*/
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
+		0x0E11, 0x4031, 0, 0, 0},       /* SA 2SL*/
+	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_SMART2P,
+		0x0E11, 0x4030, 0, 0, 0},       /* SA 2P */
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, cpqarray_pci_device_id);
+
 static struct gendisk *ida_gendisk[MAX_CTLR][NWD];
 
 /* Debug... */
@@ -108,7 +136,7 @@
 /* Debug Extra Paranoid... */
 #define DBGPX(s) do { } while(0)
 
-static int cpqarray_pci_detect(void);
+int cpqarray_init_step2(void);
 static int cpqarray_pci_init(ctlr_info_t *c, struct pci_dev *pdev);
 static void *remap_pci_mem(ulong base, ulong size);
 static int cpqarray_eisa_detect(void);
@@ -119,6 +147,9 @@
 static cmdlist_t * cmd_alloc(ctlr_info_t *h, int get_from_pool);
 static void cmd_free(ctlr_info_t *h, cmdlist_t *c, int got_from_pool);
 
+static void free_hba(int i);
+static int alloc_cpqarray_hba(void);
+
 static int sendcmd(
 	__u8	cmd,
 	int	ctlr,
@@ -145,6 +176,7 @@
 static void ida_timer(unsigned long tdata);
 static int ida_revalidate(struct gendisk *disk);
 static int revalidate_allvol(ctlr_info_t *host);
+static int cpqarray_register_ctlr(int ctlr, struct pci_dev *pdev);
 
 #ifdef CONFIG_PROC_FS
 static void ida_procinit(int i);
@@ -224,7 +256,7 @@
 		(unsigned long)h->board_id,
 		h->firm_rev[0], h->firm_rev[1], h->firm_rev[2], h->firm_rev[3],
 		(unsigned long)h->ctlr_sig, (unsigned long)h->vaddr,
-		(unsigned int) h->ioaddr, (unsigned int)h->intr,
+		(unsigned int) h->io_mem_addr, (unsigned int)h->intr,
 		h->log_drives, h->phys_drives,
 		h->Qdepth, h->maxQsinceinit);
 
@@ -281,150 +313,188 @@
 
 MODULE_PARM(eisa, "1-8i");
 
-static void __exit cpqarray_exit(void)
+/* This is a bit of a hack,
+ * necessary to support both eisa and pci
+ */
+int __init cpqarray_init(void)
+{
+	return (cpqarray_init_step2());
+}
+
+static void release_io_mem(ctlr_info_t *c)
 {
-	int i, j;
-	char buff[4]; 
+	/* if IO mem was not protected do nothing */
+	if( c->io_mem_addr == 0)
+		return;
+	release_region(c->io_mem_addr, c->io_mem_length);
+	c->io_mem_addr = 0;
+	c->io_mem_length = 0;
+}
 
-	for(i=0; i<nr_ctlr; i++) {
+static void __devexit cpqarray_remove_one(int i)
+{
+	int j;
+	char buff[4];
 
-		/* sendcmd will turn off interrupt, and send the flush... 
-		 * To write all data in the battery backed cache to disks    
-		 * no data returned, but don't want to send NULL to sendcmd */	
-		if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
-		{
-			printk(KERN_WARNING "Unable to flush cache on "
-				"controller %d\n", i);	
-		}
-		free_irq(hba[i]->intr, hba[i]);
-		iounmap(hba[i]->vaddr);
-		unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname);
-		del_timer(&hba[i]->timer);
-		blk_cleanup_queue(hba[i]->queue);
-		remove_proc_entry(hba[i]->devname, proc_array);
-		pci_free_consistent(hba[i]->pci_dev, 
-			NR_CMDS * sizeof(cmdlist_t), (hba[i]->cmd_pool), 
+	/* sendcmd will turn off interrupt, and send the flush...
+	 * To write all data in the battery backed cache to disks
+	 * no data returned, but don't want to send NULL to sendcmd */
+	if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
+	{
+		printk(KERN_WARNING "Unable to flush cache on controller %d\n",
+				i);
+	}
+	free_irq(hba[i]->intr, hba[i]);
+	iounmap(hba[i]->vaddr);
+	unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname);
+	del_timer(&hba[i]->timer);
+	remove_proc_entry(hba[i]->devname, proc_array);
+	pci_free_consistent(hba[i]->pci_dev,
+			NR_CMDS * sizeof(cmdlist_t), (hba[i]->cmd_pool),
 			hba[i]->cmd_pool_dhandle);
-		kfree(hba[i]->cmd_pool_bits);
+	kfree(hba[i]->cmd_pool_bits);
+	for(j = 0; j < NWD; j++) {
+		if (ida_gendisk[i][j]->flags & GENHD_FL_UP)
+			del_gendisk(ida_gendisk[i][j]);
+		devfs_remove("ida/c%dd%d",i,j);
+		put_disk(ida_gendisk[i][j]);
+	}
+	blk_cleanup_queue(hba[i]->queue);
+	release_io_mem(hba[i]);
+	free_hba(i);
+}
 
-		for (j = 0; j < NWD; j++) {
-			if (ida_gendisk[i][j]->flags & GENHD_FL_UP)
-				del_gendisk(ida_gendisk[i][j]);
-			devfs_remove("ida/c%dd%d",i,j);
-			put_disk(ida_gendisk[i][j]);
-		}
+static void __devexit cpqarray_remove_one_pci (struct pci_dev *pdev)
+{
+	int i;
+	ctlr_info_t *tmp_ptr;
+
+	if (pci_get_drvdata(pdev) == NULL) {
+		printk( KERN_ERR "cpqarray: Unable to remove device \n");
+		return;
 	}
-	devfs_remove("ida");
-	remove_proc_entry("cpqarray", proc_root_driver);
+
+	tmp_ptr = pci_get_drvdata(pdev);
+	i = tmp_ptr->ctlr;
+	if (hba[i] == NULL) {
+		printk(KERN_ERR "cpqarray: controller %d appears to have"
+			"already been removed \n", i);
+		return;
+        }
+	pci_set_drvdata(pdev, NULL);
+
+	cpqarray_remove_one(i);
 }
 
-/*
- *  This is it.  Find all the controllers and register them.  I really hate
- *  stealing all these major device numbers.
- *  returns the number of block devices registered.
+/* removing an instance that was not removed automatically..
+ * must be an eisa card.
  */
-static int __init cpqarray_init(void)
+static void __devexit cpqarray_remove_one_eisa (int i)
 {
-	request_queue_t *q;
-	int i,j;
-	int num_cntlrs_reg = 0;
-	/* detect controllers */
-	cpqarray_pci_detect();
-	cpqarray_eisa_detect();
-	
-	if (nr_ctlr == 0)
-		return -ENODEV;
+	if (hba[i] == NULL) {
+		printk(KERN_ERR "cpqarray: controller %d appears to have"
+			"already been removed \n", i);
+		return;
+        }
+	cpqarray_remove_one(i);
+}
 
-	printk(DRIVER_NAME "\n");
-	printk("Found %d controller(s)\n", nr_ctlr);
+/* pdev is NULL for eisa */
+static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
+{
+	request_queue_t *q;
+	int j;
 
-	/* allocate space for disk structs */
 	/* 
 	 * register block devices
 	 * Find disks and fill in structs
 	 * Get an interrupt, set the Q depth and get into /proc
 	 */
-	for(i=0; i < nr_ctlr; i++) {
-	  	/* If this successful it should insure that we are the only */
-		/* instance of the driver */	
-		if (register_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname))
-                        continue;
-
-		hba[i]->access.set_intr_mask(hba[i], 0);
-		if (request_irq(hba[i]->intr, do_ida_intr,
-			SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i])) {
 
-			printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n", 
+	/* If this successful it should insure that we are the only */
+	/* instance of the driver */
+	if (register_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname)) {
+		goto Enomem4;
+	}
+	hba[i]->access.set_intr_mask(hba[i], 0);
+	if (request_irq(hba[i]->intr, do_ida_intr,
+		SA_INTERRUPT|SA_SHIRQ, hba[i]->devname, hba[i]))
+	{
+		printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
 				hba[i]->intr, hba[i]->devname);
-			unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname);
-			continue;
-		}
-		num_cntlrs_reg++;
-		for (j=0; j<NWD; j++) {
-			ida_gendisk[i][j] = alloc_disk(1 << NWD_SHIFT);
-			if (!ida_gendisk[i][j])
-				goto Enomem2;
-		}
-		hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(
-				hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t), 
-				&(hba[i]->cmd_pool_dhandle));
-		hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
+		goto Enomem3;
+	}
 		
-		if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool)
-			goto Enomem1;
-		memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
-		memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
-		printk(KERN_INFO "cpqarray: Finding drives on %s", 
-			hba[i]->devname);
-
-		spin_lock_init(&hba[i]->lock);
-		q = blk_init_queue(do_ida_request, &hba[i]->lock);
-		if (!q)
+	for (j=0; j<NWD; j++) {
+		ida_gendisk[i][j] = alloc_disk(1 << NWD_SHIFT);
+		if (!ida_gendisk[i][j])
+			goto Enomem2;
+	}
+
+	hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(
+		hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t),
+		&(hba[i]->cmd_pool_dhandle));
+	hba[i]->cmd_pool_bits = kmalloc(
+		((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long),
+		GFP_KERNEL);
+
+	if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool)
 			goto Enomem1;
 
-		hba[i]->queue = q;
-		q->queuedata = hba[i];
+	memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
+	memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
+	printk(KERN_INFO "cpqarray: Finding drives on %s",
+		hba[i]->devname);
 
-		getgeometry(i);
-		start_fwbk(i); 
+	spin_lock_init(&hba[i]->lock);
+	q = blk_init_queue(do_ida_request, &hba[i]->lock);
+	if (!q)
+		goto Enomem1;
 
-		ida_procinit(i);
+	hba[i]->queue = q;
+	q->queuedata = hba[i];
 
+	getgeometry(i);
+	start_fwbk(i);
+
+	ida_procinit(i);
+
+	if (pdev)
 		blk_queue_bounce_limit(q, hba[i]->pci_dev->dma_mask);
 
-		/* This is a hardware imposed limit. */
-		blk_queue_max_hw_segments(q, SG_MAX);
+	/* This is a hardware imposed limit. */
+	blk_queue_max_hw_segments(q, SG_MAX);
 
-		/* This is a driver limit and could be eliminated. */
-		blk_queue_max_phys_segments(q, SG_MAX);
+	/* This is a driver limit and could be eliminated. */
+	blk_queue_max_phys_segments(q, SG_MAX);
 	
-		init_timer(&hba[i]->timer);
-		hba[i]->timer.expires = jiffies + IDA_TIMER;
-		hba[i]->timer.data = (unsigned long)hba[i];
-		hba[i]->timer.function = ida_timer;
-		add_timer(&hba[i]->timer);
-
-		/* Enable IRQ now that spinlock and rate limit timer are set up */
-		hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
-
-		for(j=0; j<NWD; j++) {
-			struct gendisk *disk = ida_gendisk[i][j];
-			drv_info_t *drv = &hba[i]->drv[j];
-			sprintf(disk->disk_name, "ida/c%dd%d", i, j);
-			disk->major = COMPAQ_SMART2_MAJOR + i;
-			disk->first_minor = j<<NWD_SHIFT;
-			disk->fops = &ida_fops; 
-			if (j && !drv->nr_blks)
-				continue;
-			blk_queue_hardsect_size(hba[i]->queue, drv->blk_size);
-			set_capacity(disk, drv->nr_blks);
-			disk->queue = hba[i]->queue;
-			disk->private_data = drv;
-			add_disk(disk);
-		}
+	init_timer(&hba[i]->timer);
+	hba[i]->timer.expires = jiffies + IDA_TIMER;
+	hba[i]->timer.data = (unsigned long)hba[i];
+	hba[i]->timer.function = ida_timer;
+	add_timer(&hba[i]->timer);
+
+	/* Enable IRQ now that spinlock and rate limit timer are set up */
+	hba[i]->access.set_intr_mask(hba[i], FIFO_NOT_EMPTY);
+
+	for(j=0; j<NWD; j++) {
+		struct gendisk *disk = ida_gendisk[i][j];
+		drv_info_t *drv = &hba[i]->drv[j];
+		sprintf(disk->disk_name, "ida/c%dd%d", i, j);
+		disk->major = COMPAQ_SMART2_MAJOR + i;
+		disk->first_minor = j<<NWD_SHIFT;
+		disk->fops = &ida_fops;
+		if (j && !drv->nr_blks)
+			continue;
+		blk_queue_hardsect_size(hba[i]->queue, drv->blk_size);
+		set_capacity(disk, drv->nr_blks);
+		disk->queue = hba[i]->queue;
+		disk->private_data = drv;
+		add_disk(disk);
 	}
+
 	/* done ! */
-	return num_cntlrs_reg ? 0 : -ENODEV;
+	return(i);
 
 Enomem1:
 	nr_ctlr = i; 
@@ -438,83 +508,105 @@
 		ida_gendisk[i][j] = NULL;
 	}
 	free_irq(hba[i]->intr, hba[i]);
+Enomem3:
 	unregister_blkdev(COMPAQ_SMART2_MAJOR+i, hba[i]->devname);
-	num_cntlrs_reg--;
+Enomem4:
+	if (pdev)
+		pci_set_drvdata(pdev, NULL);
+	release_io_mem(hba[i]);
+	free_hba(i);
+
 	printk( KERN_ERR "cpqarray: out of memory");
 
-	if (!num_cntlrs_reg) {
-		remove_proc_entry("cpqarray", proc_root_driver);
-		return -ENODEV;
+	return -1;
+}
+
+static int __init cpqarray_init_one( struct pci_dev *pdev,
+	const struct pci_device_id *ent)
+{
+	int i;
+
+	printk(KERN_DEBUG "cpqarray: Device 0x%x has been found at"
+			" bus %d dev %d func %d\n",
+			pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
+			PCI_FUNC(pdev->devfn));
+	i = alloc_cpqarray_hba();
+	if( i < 0 )
+		return (-1);
+	memset(hba[i], 0, sizeof(ctlr_info_t));
+	sprintf(hba[i]->devname, "ida%d", i);
+	hba[i]->ctlr = i;
+	/* Initialize the pdev driver private data */
+	pci_set_drvdata(pdev, hba[i]);
+
+	if (cpqarray_pci_init(hba[i], pdev) != 0) {
+		pci_set_drvdata(pdev, NULL);
+		release_io_mem(hba[i]);
+		free_hba(i);
+		return -1;
 	}
-	return 0;
+
+	return (cpqarray_register_ctlr(i, pdev));
 }
 
+static struct pci_driver cpqarray_pci_driver = {
+	name:   "cpqarray",
+	probe:  cpqarray_init_one,
+	remove:  __devexit_p(cpqarray_remove_one_pci),
+	id_table:  cpqarray_pci_device_id,
+};
+
 /*
- * Find the controller and initialize it
- *  Cannot use the class code to search, because older array controllers use
- *    0x018000 and new ones use 0x010400.  So I might as well search for each
- *    each device IDs, being there are only going to be three of them. 
- */
-static int cpqarray_pci_detect(void)
-{
-	struct pci_dev *pdev;
-
-#define IDA_BOARD_TYPES 3
-	static int ida_vendor_id[IDA_BOARD_TYPES] = { PCI_VENDOR_ID_DEC, 
-		PCI_VENDOR_ID_NCR, PCI_VENDOR_ID_COMPAQ };
-	static int ida_device_id[IDA_BOARD_TYPES] = { PCI_DEVICE_ID_COMPAQ_42XX,		PCI_DEVICE_ID_NCR_53C1510, PCI_DEVICE_ID_COMPAQ_SMART2P };
-	int brdtype;
+ *  This is it.  Find all the controllers and register them.
+ *  returns the number of block devices registered.
+ */
+int __init cpqarray_init_step2(void)
+{
+	int num_cntlrs_reg = 0;
+	int i;
+	int rc = 0;
+
+	/* detect controllers */
+	printk(DRIVER_NAME "\n");
+/* TODO: If it's an eisa only system, will rc return negative? */
+	rc = pci_register_driver(&cpqarray_pci_driver);
+	if (rc < 0)
+		return rc;
+	cpqarray_eisa_detect();
 	
-	/* search for all PCI board types that could be for this driver */
-	for(brdtype=0; brdtype<IDA_BOARD_TYPES; brdtype++)
-	{
-		pdev = pci_find_device(ida_vendor_id[brdtype],
-				       ida_device_id[brdtype], NULL);
-		while (pdev) {
-			printk(KERN_DEBUG "cpqarray: Device 0x%x has"
-				" been found at bus %d dev %d func %d\n",
-				ida_vendor_id[brdtype],
-				pdev->bus->number, PCI_SLOT(pdev->devfn),
-				PCI_FUNC(pdev->devfn));
-			if (nr_ctlr == 8) {
-				printk(KERN_WARNING "cpqarray: This driver"
-				" supports a maximum of 8 controllers.\n");
-				break;
-			}
-			
-/* if it is a PCI_DEVICE_ID_NCR_53C1510, make sure it's 				the Compaq version of the chip */ 
+	for (i=0; i < MAX_CTLR; i++) {
+		if (hba[i] != NULL)
+			num_cntlrs_reg++;
+	}
 
-			if (ida_device_id[brdtype] == PCI_DEVICE_ID_NCR_53C1510)			{	
-				unsigned short subvendor=pdev->subsystem_vendor;
-				if(subvendor !=  PCI_VENDOR_ID_COMPAQ)
-				{
-					printk(KERN_DEBUG 
-						"cpqarray: not a Compaq integrated array controller\n");
-					continue;
-				}
-			}
+	return(num_cntlrs_reg);
+}
 
-			hba[nr_ctlr] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);			if(hba[nr_ctlr]==NULL)
-			{
+/* Function to find the first free pointer into our hba[] array */
+/* Returns -1 if no free entries are left.  */
+static int alloc_cpqarray_hba(void)
+{
+	int i;
+
+	for(i=0; i< MAX_CTLR; i++) {
+		if (hba[i] == NULL) {
+			hba[i] = kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
+			if(hba[i]==NULL) {
 				printk(KERN_ERR "cpqarray: out of memory.\n");
-				continue;
-			}
-			memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
-			if (cpqarray_pci_init(hba[nr_ctlr], pdev) != 0)
-			{
-				kfree(hba[nr_ctlr]);
-				continue;
+				return (-1);
 			}
-			sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
-			hba[nr_ctlr]->ctlr = nr_ctlr;
-			nr_ctlr++;
-
-			pdev = pci_find_device(ida_vendor_id[brdtype],
-					       ida_device_id[brdtype], pdev);
+			return (i);
 		}
 	}
+	printk(KERN_WARNING "cpqarray: This driver supports a maximum"
+		" of 8 controllers.\n");
+	return(-1);
+}
 
-	return nr_ctlr;
+static void free_hba(int i)
+{
+	kfree(hba[i]);
+	hba[i]=NULL;
 }
 
 /*
@@ -556,6 +648,13 @@
 
 	pci_read_config_dword(pdev, 0x2c, &board_id);
 
+	/* check to see if controller has been disabled */
+	if(!(command & 0x02)) {
+		printk(KERN_WARNING
+			"cpqarray: controller appears to be disabled\n");
+		return(-1);
+	}
+
 DBGINFO(
 	printk("vendor_id = %x\n", vendor_id);
 	printk("device_id = %x\n", device_id);
@@ -570,11 +669,28 @@
 );
 
 	c->intr = irq;
-	c->ioaddr = addr[0];
+
+	for(i=0; i<6; i++) {
+		if (pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)
+		{ /* IO space */
+			c->io_mem_addr = addr[i];
+			c->io_mem_length = pci_resource_end(pdev, i)
+				- pci_resource_start(pdev, i) + 1;
+			if(!request_region( c->io_mem_addr, c->io_mem_length,
+				"cpqarray"))
+			{
+				printk( KERN_WARNING "cpqarray I/O memory range already in use addr %lx length = %ld\n", c->io_mem_addr, c->io_mem_length);
+				c->io_mem_addr = 0;
+				c->io_mem_length = 0;
+			}
+			break;
+		}
+	}
 
 	c->paddr = 0;
 	for(i=0; i<6; i++)
-		if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
+		if (!(pci_resource_flags(pdev, i) &
+				PCI_BASE_ADDRESS_SPACE_IO)) {
 			c->paddr = pci_resource_start (pdev, i);
 			break;
 		}
@@ -654,13 +770,13 @@
 	int i=0, j;
 	__u32 board_id;
 	int intr;
+	int ctlr;
+	int num_ctlr = 0;
 
 	while(i<8 && eisa[i]) {
-		if (nr_ctlr == 8) {
-			printk(KERN_WARNING "cpqarray: This driver supports"
-				" a maximum of 8 controllers.\n");
+		ctlr = alloc_cpqarray_hba();
+		if(ctlr == -1)
 			break;
-		}
 		board_id = inl(eisa[i]+0xC80);
 		for(j=0; j < NR_PRODUCTS; j++)
 			if (board_id == products[j].board_id) 
@@ -671,14 +787,21 @@
 				" to access the SMART Array controller %08lx\n",				 (unsigned long)board_id);
 			continue;
 		}
-		hba[nr_ctlr] = (ctlr_info_t *) kmalloc(sizeof(ctlr_info_t), GFP_KERNEL);
-		if(hba[nr_ctlr]==NULL)
+
+		memset(hba[ctlr], 0, sizeof(ctlr_info_t));
+		hba[ctlr]->io_mem_addr = eisa[i];
+		hba[ctlr]->io_mem_length = 0x7FF;
+		if(!request_region(hba[ctlr]->io_mem_addr,
+				hba[ctlr]->io_mem_length,
+				"cpqarray"))
 		{
-			printk(KERN_ERR "cpqarray: out of memory.\n");
+			printk(KERN_WARNING "cpqarray: I/O range already in "
+					"use addr = %lx length = %ld\n",
+					hba[ctlr]->io_mem_addr,
+					hba[ctlr]->io_mem_length);
+			free_hba(ctlr);
 			continue;
 		}
-		memset(hba[nr_ctlr], 0, sizeof(ctlr_info_t));
-		hba[nr_ctlr]->ioaddr = eisa[i];
 
 		/*
 		 * Read the config register to find our interrupt
@@ -689,13 +812,13 @@
 		else if (intr & 4) intr = 14;
 		else if (intr & 8) intr = 15;
 		
-		hba[nr_ctlr]->intr = intr;
-		sprintf(hba[nr_ctlr]->devname, "ida%d", nr_ctlr);
-		hba[nr_ctlr]->product_name = products[j].product_name;
-		hba[nr_ctlr]->access = *(products[j].access);
-		hba[nr_ctlr]->ctlr = nr_ctlr;
-		hba[nr_ctlr]->board_id = board_id;
-		hba[nr_ctlr]->pci_dev = NULL; /* not PCI */
+		hba[ctlr]->intr = intr;
+		sprintf(hba[ctlr]->devname, "ida%d", nr_ctlr);
+		hba[ctlr]->product_name = products[j].product_name;
+		hba[ctlr]->access = *(products[j].access);
+		hba[ctlr]->ctlr = ctlr;
+		hba[ctlr]->board_id = board_id;
+		hba[ctlr]->pci_dev = NULL; /* not PCI */
 
 DBGINFO(
 	printk("i = %d, j = %d\n", i, j);
@@ -704,14 +827,19 @@
 	printk("board_id = %x\n", board_id);
 );
 
-		nr_ctlr++;
+		num_ctlr++;
 		i++;
+
+		if (cpqarray_register_ctlr(ctlr, NULL) == -1)
+			printk(KERN_WARNING
+				"cpqarray: Can't register EISA controller %d\n",
+				ctlr);
+
 	}
 
-	return nr_ctlr;
+	return num_ctlr;
 }
 
-
 /*
  * Open.  Make sure the device is really there.
  */
@@ -1610,7 +1738,7 @@
                 return;
         }
 
-	info_p->log_drives = id_ctlr_buf->nr_drvs;;
+	info_p->log_drives = id_ctlr_buf->nr_drvs;
 	for(i=0;i<4;i++)
 		info_p->firm_rev[i] = id_ctlr_buf->firm_rev[i];
 	info_p->ctlr_sig = id_ctlr_buf->cfg_sig;
@@ -1719,6 +1847,25 @@
 	kfree(id_ctlr_buf);
 	return;
 
+}
+
+static void __exit cpqarray_exit(void)
+{
+	int i;
+
+	pci_unregister_driver(&cpqarray_pci_driver);
+
+	/* Double check that all controller entries have been removed */
+	for(i=0; i<MAX_CTLR; i++) {
+		if (hba[i] != NULL) {
+			printk(KERN_WARNING "cpqarray: Removing EISA "
+					"controller %d\n", i);
+			cpqarray_remove_one_eisa(i);
+		}
+	}
+
+	devfs_remove("ida");
+	remove_proc_entry("cpqarray", proc_root_driver);
 }
 
 module_init(cpqarray_init)
diff -Nru a/drivers/block/cpqarray.h b/drivers/block/cpqarray.h
--- a/drivers/block/cpqarray.h	Sat Apr  3 19:38:45 2004
+++ b/drivers/block/cpqarray.h	Sat Apr  3 19:38:45 2004
@@ -92,7 +92,8 @@
 
 	void *vaddr;
 	unsigned long paddr;
-	unsigned long ioaddr;
+	unsigned long io_mem_addr;
+	unsigned long io_mem_length;
 	int	intr;
 	int	usage_count;
 	drv_info_t	drv[NWD];
diff -Nru a/drivers/block/elevator.c b/drivers/block/elevator.c
--- a/drivers/block/elevator.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/block/elevator.c	Sat Apr  3 19:38:55 2004
@@ -210,10 +210,14 @@
 			rq = NULL;
 			break;
 		} else if (ret == BLKPREP_KILL) {
+			int nr_bytes = rq->hard_nr_sectors << 9;
+
+			if (!nr_bytes)
+				nr_bytes = rq->data_len;
+
 			blkdev_dequeue_request(rq);
 			rq->flags |= REQ_QUIET;
-			while (end_that_request_first(rq, 0, rq->nr_sectors))
-				;
+			end_that_request_chunk(rq, 0, nr_bytes);
 			end_that_request_last(rq);
 		} else {
 			printk("%s: bad return=%d\n", __FUNCTION__, ret);
diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/block/genhd.c	Sat Apr  3 19:38:43 2004
@@ -184,7 +184,7 @@
 }
 
 /**
- * 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 -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/block/ll_rw_blk.c	Sat Apr  3 19:38:41 2004
@@ -28,6 +28,11 @@
 #include <linux/slab.h>
 #include <linux/swap.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);
 
@@ -42,7 +47,10 @@
 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];
+static wait_queue_head_t congestion_wqh[2] = {
+		__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
+		__WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
+	};
 
 /*
  * Controlling structure to kblockd
@@ -104,6 +112,7 @@
 
 	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);
 }
@@ -1136,8 +1145,6 @@
 	if (!blk_remove_plug(q))
 		return;
 
-	del_timer(&q->unplug_timer);
-
 	/*
 	 * was plugged, fire request_fn if queue has stuff to do
 	 */
@@ -1543,7 +1550,6 @@
 	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 +1631,7 @@
 	rq->rl = rl;
 	rq->waiting = NULL;
 	rq->special = NULL;
+	rq->data_len = 0;
 	rq->data = NULL;
 	rq->sense = NULL;
 
@@ -1770,6 +1777,144 @@
 
 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 +2043,17 @@
  * 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);
@@ -1940,6 +2087,15 @@
 	if (!q->merge_requests_fn(q, req, next))
 		return 0;
 
+	/*
+	 * At this point we have either done a back merge
+	 * or front merge. We need the smaller start_time of
+	 * the merged requests to be the current request
+	 * for accounting purposes.
+	 */
+	if (time_after(req->start_time, next->start_time))
+		req->start_time = next->start_time;
+
 	req->biotail->bi_next = next->bio;
 	req->biotail = next->biotail;
 
@@ -2681,8 +2837,6 @@
 
 int __init blk_dev_init(void)
 {
-	int i;
-
 	kblockd_workqueue = create_workqueue("kblockd");
 	if (!kblockd_workqueue)
 		panic("Failed to create kblockd\n");
@@ -2694,9 +2848,6 @@
 
 	blk_max_low_pfn = max_low_pfn;
 	blk_max_pfn = max_pfn;
-
-	for (i = 0; i < ARRAY_SIZE(congestion_wqh); i++)
-		init_waitqueue_head(&congestion_wqh[i]);
 	return 0;
 }
 
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/block/loop.c	Sat Apr  3 19:38:44 2004
@@ -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 @@
 	&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 @@
 	 * Unfortunately, if we want to do I/O on the device,
 	 * the number of 512-byte sectors has to fit into a sector_t.
 	 */
-	size = loopsize >> 9;
-	x = (sector_t)size;
+	return loopsize >> 9;
+}
+
+static int
+figure_loop_size(struct loop_device *lo)
+{
+	loff_t size = get_loop_size(lo, lo->lo_backing_file);
+	sector_t x = (sector_t)size;
 
 	if ((loff_t)x != size)
 		return -EFBIG;
@@ -429,12 +434,24 @@
 	goto out;
 }
 
+struct switch_request {
+	struct file *file;
+	struct completion wait;
+};
+
+static void do_loop_switch(struct loop_device *, struct switch_request *);
+
 static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio)
 {
 	int ret;
 
-	ret = do_bio_filebacked(lo, bio);
-	bio_endio(bio, bio->bi_size, ret);
+	if (unlikely(!bio->bi_bdev)) {
+		do_loop_switch(lo, bio->bi_private);
+		bio_put(bio);
+	} else {
+		ret = do_bio_filebacked(lo, bio);
+		bio_endio(bio, bio->bi_size, ret);
+	}
 }
 
 /*
@@ -495,6 +512,103 @@
 	return 0;
 }
 
+/*
+ * loop_switch performs the hard work of switching a backing store.
+ * First it needs to flush existing IO, it does this by sending a magic
+ * BIO down the pipe. The completion of this BIO does the actual switch.
+ */
+static int loop_switch(struct loop_device *lo, struct file *file)
+{
+	struct switch_request w;
+	struct bio *bio = bio_alloc(GFP_KERNEL, 1);
+	if (!bio)
+		return -ENOMEM;
+	init_completion(&w.wait);
+	w.file = file;
+	bio->bi_private = &w;
+	bio->bi_bdev = NULL;
+	loop_make_request(lo->lo_queue, bio);
+	wait_for_completion(&w.wait);
+	return 0;
+}
+
+/*
+ * Do the actual switch; called from the BIO completion routine
+ */
+static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
+{
+	struct file *file = p->file;
+	struct file *old_file = lo->lo_backing_file;
+	struct address_space *mapping = file->f_mapping;
+
+	mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
+	lo->lo_backing_file = file;
+	lo->lo_blocksize = mapping->host->i_blksize;
+	lo->old_gfp_mask = mapping_gfp_mask(mapping);
+	mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
+	complete(&p->wait);
+}
+
+
+/*
+ * loop_change_fd switched the backing store of a loopback device to
+ * a new file. This is useful for operating system installers to free up
+ * the original file and in High Availability environments to switch to
+ * an alternative location for the content in case of server meltdown.
+ * This can only work if the loop device is used read-only, and if the
+ * new backing store is the same size and type as the old backing store.
+ */
+static int loop_change_fd(struct loop_device *lo, struct file *lo_file,
+		       struct block_device *bdev, unsigned int arg)
+{
+	struct file	*file, *old_file;
+	struct inode	*inode;
+	int		error;
+
+	error = -ENXIO;
+	if (lo->lo_state != Lo_bound)
+		goto out;
+
+	/* the loop device has to be read-only */
+	error = -EINVAL;
+	if (lo->lo_flags != LO_FLAGS_READ_ONLY)
+		goto out;
+
+	error = -EBADF;
+	file = fget(arg);
+	if (!file)
+		goto out;
+
+	inode = file->f_mapping->host;
+	old_file = lo->lo_backing_file;
+
+	error = -EINVAL;
+
+	if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
+		goto out_putf;
+
+	/* new backing store needs to support loop (eg sendfile) */
+	if (!inode->i_fop->sendfile)
+		goto out_putf;
+
+	/* size of the new backing store needs to be the same */
+	if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
+		goto out_putf;
+
+	/* and ... switch */
+	error = loop_switch(lo, file);
+	if (error)
+		goto out_putf;
+
+	fput(old_file);
+	return 0;
+
+ out_putf:
+	fput(file);
+ out:
+	return error;
+}
+
 static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
 		       struct block_device *bdev, unsigned int arg)
 {
@@ -505,6 +619,7 @@
 	unsigned lo_blocksize;
 	int		lo_flags = 0;
 	int		error;
+	loff_t		size;
 
 	/* This is safe, since we have a reference from open(). */
 	__module_get(THIS_MODULE);
@@ -543,6 +658,13 @@
 		goto out_putf;
 	}
 
+	size = get_loop_size(lo, file);
+
+	if ((loff_t)(sector_t)size != size) {
+		error = -EFBIG;
+		goto out_putf;
+	}
+
 	if (!(lo_file->f_mode & FMODE_WRITE))
 		lo_flags |= LO_FLAGS_READ_ONLY;
 
@@ -555,10 +677,6 @@
 	lo->transfer = NULL;
 	lo->ioctl = NULL;
 	lo->lo_sizelimit = 0;
-	if (figure_loop_size(lo)) {
-		error = -EFBIG;
-		goto out_putf;
-	}
 	lo->old_gfp_mask = mapping_gfp_mask(mapping);
 	mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
 
@@ -571,6 +689,9 @@
 	blk_queue_make_request(lo->lo_queue, loop_make_request);
 	lo->lo_queue->queuedata = lo;
 
+	set_capacity(disks[lo->lo_number], size);
+	bd_set_size(bdev, size << 9);
+
 	set_blocksize(bdev, lo_blocksize);
 
 	kernel_thread(loop_thread, lo, CLONE_KERNEL);
@@ -660,6 +781,7 @@
 	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);
@@ -880,6 +1002,9 @@
 	switch (cmd) {
 	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);
diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c
--- a/drivers/block/scsi_ioctl.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/block/scsi_ioctl.c	Sat Apr  3 19:38:56 2004
@@ -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 @@
 	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 @@
 	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 @@
 		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 @@
 			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 @@
 
 	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 @@
 	 * (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 @@
 			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)
@@ -369,7 +287,7 @@
 	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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 }
 
 EXPORT_SYMBOL(scsi_cmd_ioctl);
-EXPORT_SYMBOL(scsi_command_size);
diff -Nru a/drivers/block/smart1,2.h b/drivers/block/smart1,2.h
--- a/drivers/block/smart1,2.h	Sat Apr  3 19:38:44 2004
+++ b/drivers/block/smart1,2.h	Sat Apr  3 19:38:44 2004
@@ -156,27 +156,27 @@
  */
 static void smart2e_submit_command(ctlr_info_t *h, cmdlist_t *c)
 {
-	outl(c->busaddr, h->ioaddr + COMMAND_FIFO);
+	outl(c->busaddr, h->io_mem_addr + COMMAND_FIFO);
 }
 
 static void smart2e_intr_mask(ctlr_info_t *h, unsigned long val)
 {
-	outl(val, h->ioaddr + INTR_MASK);
+	outl(val, h->io_mem_addr + INTR_MASK);
 }
 
 static unsigned long smart2e_fifo_full(ctlr_info_t *h)
 {
-	return inl(h->ioaddr + COMMAND_FIFO);
+	return inl(h->io_mem_addr + COMMAND_FIFO);
 }
 
 static unsigned long smart2e_completed(ctlr_info_t *h)
 {
-	return inl(h->ioaddr + COMMAND_COMPLETE_FIFO);
+	return inl(h->io_mem_addr + COMMAND_COMPLETE_FIFO);
 }
 
 static unsigned long smart2e_intr_pending(ctlr_info_t *h)
 {
-	return inl(h->ioaddr + INTR_PENDING);
+	return inl(h->io_mem_addr + INTR_PENDING);
 }
 
 static struct access_method smart2e_access = {
@@ -212,30 +212,30 @@
 	 */
 	c->hdr.size = 0;
 
-	outb(CHANNEL_CLEAR, h->ioaddr + SMART1_SYSTEM_DOORBELL);
+	outb(CHANNEL_CLEAR, h->io_mem_addr + SMART1_SYSTEM_DOORBELL);
 
-	outl(c->busaddr, h->ioaddr + SMART1_LISTADDR);
-	outw(c->size, h->ioaddr + SMART1_LISTLEN);
+	outl(c->busaddr, h->io_mem_addr + SMART1_LISTADDR);
+	outw(c->size, h->io_mem_addr + SMART1_LISTLEN);
 
-	outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL);
+	outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_LOCAL_DOORBELL);
 }
 
 static void smart1_intr_mask(ctlr_info_t *h, unsigned long val)
 {
 	if (val == 1) {
-		outb(0xFD, h->ioaddr + SMART1_SYSTEM_DOORBELL);
-		outb(CHANNEL_BUSY, h->ioaddr + SMART1_LOCAL_DOORBELL);
-		outb(0x01, h->ioaddr + SMART1_INTR_MASK);
-		outb(0x01, h->ioaddr + SMART1_SYSTEM_MASK);
+		outb(0xFD, h->io_mem_addr + SMART1_SYSTEM_DOORBELL);
+		outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_LOCAL_DOORBELL);
+		outb(0x01, h->io_mem_addr + SMART1_INTR_MASK);
+		outb(0x01, h->io_mem_addr + SMART1_SYSTEM_MASK);
 	} else {
-		outb(0, h->ioaddr + 0xC8E);
+		outb(0, h->io_mem_addr + 0xC8E);
 	}
 }
 
 static unsigned long smart1_fifo_full(ctlr_info_t *h)
 {
 	unsigned char chan;
-	chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR;
+	chan = inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR;
 	return chan;
 }
 
@@ -244,13 +244,13 @@
 	unsigned char status;
 	unsigned long cmd;
 
-	if (inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) {
-		outb(CHANNEL_BUSY, h->ioaddr + SMART1_SYSTEM_DOORBELL);
+	if (inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) {
+		outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_SYSTEM_DOORBELL);
 
-		cmd = inl(h->ioaddr + SMART1_COMPLETE_ADDR);
-		status = inb(h->ioaddr + SMART1_LISTSTATUS);
+		cmd = inl(h->io_mem_addr + SMART1_COMPLETE_ADDR);
+		status = inb(h->io_mem_addr + SMART1_LISTSTATUS);
 
-		outb(CHANNEL_CLEAR, h->ioaddr + SMART1_LOCAL_DOORBELL);
+		outb(CHANNEL_CLEAR, h->io_mem_addr + SMART1_LOCAL_DOORBELL);
 
 		/*
 		 * this is x86 (actually compaq x86) only, so it's ok
@@ -265,7 +265,7 @@
 static unsigned long smart1_intr_pending(ctlr_info_t *h)
 {
 	unsigned char chan;
-	chan = inb(h->ioaddr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY;
+	chan = inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY;
 	return chan;
 }
 
diff -Nru a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
--- a/drivers/bluetooth/bcm203x.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/bluetooth/bcm203x.c	Sat Apr  3 19:38:40 2004
@@ -296,14 +296,15 @@
 	return err;
 }
 
-static void __exit bcm203x_cleanup(void)
+static void __exit bcm203x_exit(void)
 {
 	usb_deregister(&bcm203x_driver);
 }
 
 module_init(bcm203x_init);
-module_exit(bcm203x_cleanup);
+module_exit(bcm203x_exit);
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Broadcom Blutonium firmware driver ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
--- a/drivers/bluetooth/bfusb.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/bluetooth/bfusb.c	Sat Apr  3 19:38:54 2004
@@ -779,14 +779,15 @@
 	return err;
 }
 
-static void __exit bfusb_cleanup(void)
+static void __exit bfusb_exit(void)
 {
 	usb_deregister(&bfusb_driver);
 }
 
 module_init(bfusb_init);
-module_exit(bfusb_cleanup);
+module_exit(bfusb_exit);
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
--- a/drivers/bluetooth/hci_bcsp.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/bluetooth/hci_bcsp.c	Sat Apr  3 19:38:55 2004
@@ -512,7 +512,7 @@
 	struct bcsp_struct *bcsp = hu->priv;
 	register unsigned char *ptr;
 
-	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
+	BT_DBG("hu %p count %d rx_state %d rx_count %ld", 
 		hu, count, bcsp->rx_state, bcsp->rx_count);
 
 	ptr = data;
diff -Nru a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
--- a/drivers/bluetooth/hci_ldisc.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/bluetooth/hci_ldisc.c	Sat Apr  3 19:38:54 2004
@@ -521,7 +521,7 @@
 int bcsp_deinit(void);
 #endif
 
-int __init hci_uart_init(void)
+static int __init hci_uart_init(void)
 {
 	static struct tty_ldisc hci_uart_ldisc;
 	int err;
@@ -559,7 +559,7 @@
 	return 0;
 }
 
-void hci_uart_cleanup(void)
+static void __exit hci_uart_exit(void)
 {
 	int err;
 
@@ -576,9 +576,10 @@
 }
 
 module_init(hci_uart_init);
-module_exit(hci_uart_cleanup);
+module_exit(hci_uart_exit);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_HCI);
diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/bluetooth/hci_usb.c	Sat Apr  3 19:38:55 2004
@@ -55,7 +55,7 @@
 
 #include "hci_usb.h"
 
-#ifndef HCI_USB_DEBUG
+#ifndef CONFIG_BT_HCIUSB_DEBUG
 #undef  BT_DBG
 #define BT_DBG( A... )
 #undef  BT_DMP
@@ -73,6 +73,9 @@
 	/* Generic Bluetooth USB device */
 	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
 
+	/* AVM BlueFRITZ! USB v2.0 */
+	{ USB_DEVICE(0x057c, 0x3800) },
+
 	/* Ericsson with non-standard id */
 	{ USB_DEVICE(0x0bdb, 0x1002) },
 
@@ -795,7 +798,7 @@
 	struct hci_dev *hdev;
 	int i, a, e, size, ifn, isoc_ifnum, isoc_alts;
 
-	BT_DBG("udev %p ifnum %d", udev, ifnum);
+	BT_DBG("udev %p intf %p", udev, intf);
 
 	if (!id->driver_info) {
 		const struct usb_device_id *match;
@@ -991,7 +994,7 @@
 	.id_table   =  bluetooth_ids,
 };
 
-int hci_usb_init(void)
+static int __init hci_usb_init(void)
 {
 	int err;
 
@@ -1003,14 +1006,15 @@
 	return err;
 }
 
-void hci_usb_cleanup(void)
+static void __exit hci_usb_exit(void)
 {
 	usb_deregister(&hci_usb_driver);
 }
 
 module_init(hci_usb_init);
-module_exit(hci_usb_cleanup);
+module_exit(hci_usb_exit);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/cdrom/cdrom.c	Sat Apr  3 19:38:41 2004
@@ -406,6 +406,11 @@
 	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; 	
@@ -641,12 +646,86 @@
 	return 0;
 }
 
+int cdrom_get_random_writable(struct cdrom_device_info *cdi,
+			      struct rwrt_feature_desc *rfd)
+{
+	struct cdrom_generic_command cgc;
+	char buffer[24];
+	struct feature_header *fh;
+	int ret;
+
+	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+
+	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;	/* often 0x46 */
+	cgc.cmd[3] = CDF_RWRT;			/* often 0x0020 */
+	cgc.cmd[8] = sizeof(buffer);		/* often 0x18 */
+	cgc.quiet = 1;
+
+	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
+		return ret;
+
+	fh = (struct feature_header *)&buffer[0];
+	if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+
+					  sizeof(struct rwrt_feature_desc)))
+		memcpy(rfd, &buffer[sizeof(struct feature_header)],
+		       sizeof (*rfd));
+	else
+		memset(rfd, 0, sizeof(*rfd));
+
+	return 0;
+}
+
+int cdrom_has_defect_mgt(struct cdrom_device_info *cdi)
+{
+	struct cdrom_generic_command cgc;
+	char buffer[16];
+	struct feature_header *fh;
+	__u16 *feature_code;
+	int ret;
+
+	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+
+	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;	/* often 0x46 */
+	cgc.cmd[3] = CDF_HWDM;			/* often 0x0024 */
+	cgc.cmd[8] = sizeof(buffer);		/* often 0x10 */
+	cgc.quiet = 1;
+
+	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
+		return ret;
+
+	fh = (struct feature_header *)&buffer[0];
+	ret = 1;
+	if (be32_to_cpu(fh->data_len) >= (sizeof(struct feature_header)+8)) {
+		feature_code = (__u16 *)&buffer[sizeof(struct feature_header)];
+		if (CDF_HWDM == be16_to_cpu(*feature_code))
+			ret = 0;
+	}
+	return ret;
+}
+
+
+int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)
+{
+	struct rwrt_feature_desc rfd;
+	int ret;
+
+	*write = 0;
+
+	if ((ret = cdrom_get_random_writable(cdi, &rfd)))
+		return ret;
+
+	if (CDF_RWRT == be16_to_cpu(rfd.feature_code))
+		*write = 1;
+
+	return 0;
+}
+
 static int cdrom_media_erasable(struct cdrom_device_info *cdi)
 {
 	disc_information di;
 
 	if (cdrom_get_disc_info(cdi, &di))
-		return 0;
+		return -1;
 
 	return di.erasable;
 }
@@ -656,7 +735,16 @@
  */
 static int cdrom_dvdram_open_write(struct cdrom_device_info *cdi)
 {
-	return !cdrom_media_erasable(cdi);
+	int ret = cdrom_media_erasable(cdi);
+
+	/*
+	 * allow writable open if media info read worked and media is
+	 * erasable, _or_ if it fails since not all drives support it
+	 */
+	if (!ret)
+		return 1;
+
+	return 0;
 }
 
 static int cdrom_mrw_open_write(struct cdrom_device_info *cdi)
@@ -724,6 +812,23 @@
 	return buffer[3] & 0x80;
 }
 
+static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
+{
+	struct rwrt_feature_desc rfd;
+	int ret;
+
+	if ((ret = cdrom_has_defect_mgt(cdi)))
+		return ret;
+
+	if ((ret = cdrom_get_random_writable(cdi, &rfd)))
+		return ret;
+	else if (CDF_RWRT == be16_to_cpu(rfd.feature_code))
+		ret = !rfd.curr;
+
+	cdinfo(CD_OPEN, "can open for random write\n");
+	return ret;
+}
+
 /*
  * returns 0 for ok to open write, non-0 to disallow
  */
@@ -735,6 +840,9 @@
 		ret = cdrom_mrw_open_write(cdi);
 	else if (CDROM_CAN(CDC_DVD_RAM))
 		ret = cdrom_dvdram_open_write(cdi);
+ 	else if (CDROM_CAN(CDC_RAM) &&
+ 		 !CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW))
+ 		ret = cdrom_ram_open_write(cdi);
 	else if (CDROM_CAN(CDC_MO_DRIVE))
 		ret = mo_open_write(cdi);
 
@@ -1788,6 +1896,149 @@
 	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 +2531,7 @@
 		}
 	case CDROMREADAUDIO: {
 		struct cdrom_read_audio ra;
-		int lba, nr;
+		int lba;
 
 		IOCTL_IN(arg, struct cdrom_read_audio, ra);
 
@@ -2297,40 +2548,7 @@
 		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;
@@ -2670,6 +2888,7 @@
 EXPORT_SYMBOL(init_cdrom_command);
 EXPORT_SYMBOL(cdrom_get_media_event);
 EXPORT_SYMBOL(cdrom_is_mrw);
+EXPORT_SYMBOL(cdrom_is_random_writable);
 
 #ifdef CONFIG_SYSCTL
 
@@ -2773,6 +2992,10 @@
 	pos += sprintf(info+pos, "\nCan write MRW:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
 	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0);
+
+	pos += sprintf(info+pos, "\nCan write RAM:\t");
+	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0);
 
 	strcpy(info+pos,"\n\n");
 		
diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
--- a/drivers/cdrom/cdu31a.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/cdrom/cdu31a.c	Sat Apr  3 19:38:45 2004
@@ -3203,13 +3203,16 @@
 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 @@
 		/* 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 @@
 		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,10 +3316,8 @@
 	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
 	 * required for the Fusion CD-16 package.  If the sound driver is
@@ -3323,51 +3330,32 @@
 		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. */
+		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 -Nru a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
--- a/drivers/cdrom/cm206.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/cdrom/cm206.c	Sat Apr  3 19:38:55 2004
@@ -1389,7 +1389,7 @@
 
    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 @@
 	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 @@
 		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 -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
--- a/drivers/cdrom/sbpcd.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/cdrom/sbpcd.c	Sat Apr  3 19:38:41 2004
@@ -5120,7 +5120,7 @@
 			for ( ; try!=0;try--)
 			{
 				j=inb(CDi_status);
-				if (!(j&s_not_data_ready)) break;;
+				if (!(j&s_not_data_ready)) break;
 				if (!(j&s_not_result_ready)) break;
 				if (fam0LV_drive) if (j&s_attention) break;
 			}
diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
--- a/drivers/cdrom/sjcd.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/cdrom/sjcd.c	Sat Apr  3 19:38:45 2004
@@ -1700,7 +1700,7 @@
 	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 -Nru a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
--- a/drivers/cdrom/viocd.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/cdrom/viocd.c	Sat Apr  3 19:38:56 2004
@@ -338,8 +338,9 @@
 	struct request *req;
 
 	while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) {
-		/* check for any kind of error */
-		if (send_request(req) < 0) {
+		if (!blk_fs_request(req))
+			end_request(req, 0);
+		else if (send_request(req) < 0) {
 			printk(VIOCD_KERN_WARNING
 					"unable to send message to OS/400!");
 			end_request(req, 0);
@@ -614,7 +615,7 @@
 				VIOCD_DEVICE_DEVFS "%d", deviceno);
 		gendisk->queue = viocd_queue;
 		gendisk->fops = &viocd_fops;
-		gendisk->flags = GENHD_FL_CD;
+		gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
 		set_capacity(gendisk, 0);
 		gendisk->private_data = d;
 		d->viocd_disk = gendisk;
diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig
--- a/drivers/char/Kconfig	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/Kconfig	Sat Apr  3 19:38:41 2004
@@ -599,30 +599,6 @@
 	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 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 -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Sat Apr  3 19:38:56 2004
+++ b/drivers/char/Makefile	Sat Apr  3 19:38:56 2004
@@ -44,12 +44,12 @@
 obj-$(CONFIG_RAW_DRIVER)	+= raw.o
 obj-$(CONFIG_SGI_L1_SERIAL)	+= sn_serial.o
 obj-$(CONFIG_VIOCONS) += viocons.o
+obj-$(CONFIG_VIOTAPE)		+= viotape.o
 
 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 -Nru a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
--- a/drivers/char/agp/Kconfig	Sat Apr  3 19:38:44 2004
+++ b/drivers/char/agp/Kconfig	Sat Apr  3 19:38:44 2004
@@ -77,7 +77,7 @@
 
 config AGP_INTEL
 	tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support"
-	depends on AGP && X86
+	depends on AGP && X86 && !X86_64
 	help
 	  This option gives you AGP support for the GLX component of XFree86 4.x
 	  on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875,
@@ -87,6 +87,16 @@
 	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
 	  use GLX or DRI, or if you have any Intel integrated graphics
 	  chipsets.  If unsure, say Y.
+
+config AGP_INTEL_MCH
+	tristate "Intel i865 chipset support"
+	depends on AGP && X86
+	help
+	  This option gives you AGP support for the GLX component of XFree86 4.x
+	  on Intel chipsets that support Intel EM64T processors.
+
+	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+	  use GLX or DRI.  If unsure, say Y.
 
 config AGP_NVIDIA
 	tristate "NVIDIA nForce/nForce2 chipset support"
diff -Nru a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
--- a/drivers/char/agp/Makefile	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/agp/Makefile	Sat Apr  3 19:38:42 2004
@@ -9,6 +9,7 @@
 obj-$(CONFIG_AGP_EFFICEON)	+= efficeon-agp.o
 obj-$(CONFIG_AGP_HP_ZX1)	+= hp-agp.o
 obj-$(CONFIG_AGP_I460)		+= i460-agp.o
+obj-$(CONFIG_AGP_INTEL_MCH)		+= intel-mch-agp.o
 obj-$(CONFIG_AGP_INTEL)		+= intel-agp.o
 obj-$(CONFIG_AGP_NVIDIA)	+= nvidia-agp.o
 obj-$(CONFIG_AGP_SIS)		+= sis-agp.o
diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
--- a/drivers/char/agp/agp.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/char/agp/agp.h	Sat Apr  3 19:38:43 2004
@@ -1,6 +1,6 @@
 /*
  * AGPGART
- * Copyright (C) 2002-2003 Dave Jones
+ * Copyright (C) 2002-2004 Dave Jones
  * Copyright (C) 1999 Jeff Hartmann
  * Copyright (C) 1999 Precision Insight, Inc.
  * Copyright (C) 1999 Xi Graphics, Inc.
@@ -167,8 +167,6 @@
 
 #define PGE_EMPTY(b, p)	(!(p) || (p) == (unsigned long) (b)->scratch_page)
 
-/* Chipset independant registers (from AGP Spec) */
-#define AGP_APBASE	0x10
 
 /* Intel registers */
 #define INTEL_APSIZE	0xb4
@@ -177,14 +175,6 @@
 #define INTEL_NBXCFG	0x50
 #define INTEL_ERRSTS	0x91
 
-/* Intel 460GX Registers */
-#define INTEL_I460_BAPBASE		0x98
-#define INTEL_I460_GXBCTL		0xa0
-#define INTEL_I460_AGPSIZ		0xa2
-#define INTEL_I460_ATTBASE		0xfe200000
-#define INTEL_I460_GATT_VALID		(1UL << 24)
-#define INTEL_I460_GATT_COHERENT	(1UL << 25)
-
 /* Intel i830 registers */
 #define I830_GMCH_CTRL			0x52
 #define I830_GMCH_ENABLED		0x4
@@ -219,26 +209,10 @@
 #define I852_GME			0x2
 #define I852_GM				0x5
 
-/* Intel 815 register */
-#define INTEL_815_APCONT	0x51
-#define INTEL_815_ATTBASE_MASK	~0x1FFFFFFF
-
-/* Intel i820 registers */
-#define INTEL_I820_RDCR		0x51
-#define INTEL_I820_ERRSTS	0xc8
-
-/* Intel i840 registers */
-#define INTEL_I840_MCHCFG	0x50
-#define INTEL_I840_ERRSTS	0xc8
- 
 /* Intel i845 registers */
 #define INTEL_I845_AGPM		0x51
 #define INTEL_I845_ERRSTS	0xc8
 
-/* Intel i850 registers */
-#define INTEL_I850_MCHCFG	0x50
-#define INTEL_I850_ERRSTS	0xc8
-
 /* Intel i860 registers */
 #define INTEL_I860_MCHCFG	0x50
 #define INTEL_I860_ERRSTS	0xc8
@@ -261,110 +235,6 @@
 #define I810_DRAM_ROW_0		0x00000001
 #define I810_DRAM_ROW_0_SDRAM	0x00000001
 
-/* Intel 7505 registers */
-#define INTEL_I7505_APSIZE	0x74
-#define INTEL_I7505_NCAPID	0x60
-#define INTEL_I7505_NISTAT	0x6c
-#define INTEL_I7505_ATTBASE	0x78
-#define INTEL_I7505_ERRSTS	0x42
-#define INTEL_I7505_AGPCTRL	0x70
-#define INTEL_I7505_MCHCFG	0x50
-
-/* VIA register */
-#define VIA_GARTCTRL	0x80
-#define VIA_APSIZE	0x84
-#define VIA_ATTBASE	0x88
-
-/* VIA KT400 */
-#define VIA_AGP3_GARTCTRL	0x90
-#define VIA_AGP3_APSIZE		0x94
-#define VIA_AGP3_ATTBASE	0x98
-#define VIA_AGPSEL		0xfd
-
-/* SiS registers */
-#define SIS_ATTBASE	0x90
-#define SIS_APSIZE	0x94
-#define SIS_TLBCNTRL	0x97
-#define SIS_TLBFLUSH	0x98
-
-/* AMD registers */
-#define AMD_MMBASE	0x14
-#define AMD_APSIZE	0xac
-#define AMD_MODECNTL	0xb0
-#define AMD_MODECNTL2	0xb2
-#define AMD_GARTENABLE	0x02	/* In mmio region (16-bit register) */
-#define AMD_ATTBASE	0x04	/* In mmio region (32-bit register) */
-#define AMD_TLBFLUSH	0x0c	/* In mmio region (32-bit register) */
-#define AMD_CACHEENTRY	0x10	/* In mmio region (32-bit register) */
-
-/* AMD64 registers */
-#define AMD64_GARTAPERTURECTL	0x90
-#define AMD64_GARTAPERTUREBASE	0x94
-#define AMD64_GARTTABLEBASE	0x98
-#define AMD64_GARTCACHECTL		0x9c
-#define AMD64_GARTEN		(1<<0)
-
-/* ALi registers */
-#define ALI_AGPCTRL			0xb8
-#define ALI_ATTBASE			0xbc
-#define ALI_TLBCTRL			0xc0
-#define ALI_TAGCTRL			0xc4
-#define ALI_CACHE_FLUSH_CTRL		0xD0
-#define ALI_CACHE_FLUSH_ADDR_MASK	0xFFFFF000
-#define ALI_CACHE_FLUSH_EN		0x100
-
-/* ATI register */
-#define ATI_GART_MMBASE_ADDR	0x14
-#define ATI_RS100_APSIZE	0xac
-#define ATI_RS300_APSIZE	0xf8
-#define ATI_RS100_IG_AGPMODE	0xb0
-#define ATI_RS300_IG_AGPMODE	0xfc
-
-#define ATI_GART_FEATURE_ID		0x00
-#define ATI_GART_BASE			0x04
-#define ATI_GART_CACHE_SZBASE		0x08
-#define ATI_GART_CACHE_CNTRL		0x0c
-#define ATI_GART_CACHE_ENTRY_CNTRL	0x10
-
-/* Serverworks Registers */
-#define SVWRKS_APSIZE		0x10
-#define SVWRKS_SIZE_MASK	0xfe000000
-
-#define SVWRKS_MMBASE		0x14
-#define SVWRKS_CACHING		0x4b
-#define SVWRKS_FEATURE		0x68
-
-/* func 1 registers */
-#define SVWRKS_AGP_ENABLE	0x60
-#define SVWRKS_COMMAND		0x04
-
-/* Memory mapped registers */
-#define SVWRKS_GART_CACHE	0x02
-#define SVWRKS_GATTBASE		0x04
-#define SVWRKS_TLBFLUSH		0x10
-#define SVWRKS_POSTFLUSH	0x14
-#define SVWRKS_DIRFLUSH		0x0c
-
-/* HP ZX1 SBA registers */
-#define HP_ZX1_CTRL		0x200
-#define HP_ZX1_IBASE		0x300
-#define HP_ZX1_IMASK		0x308
-#define HP_ZX1_PCOM		0x310
-#define HP_ZX1_TCNFG		0x318
-#define HP_ZX1_PDIR_BASE	0x320
-#define HP_ZX1_CACHE_FLUSH	0x428
-
-/* NVIDIA registers */
-#define NVIDIA_0_APSIZE		0x80
-#define NVIDIA_1_WBC		0xf0
-#define NVIDIA_2_GARTCTRL	0xd0
-#define NVIDIA_2_APBASE		0xd8
-#define NVIDIA_2_APLIMIT	0xdc
-#define NVIDIA_2_ATTBASE(i)	(0xe0 + (i) * 4)
-#define NVIDIA_3_APBASE		0x50
-#define NVIDIA_3_APLIMIT	0x54
-
-
 struct agp_device_ids {
 	unsigned short device_id; /* first, to make table easier to read */
 	enum chipset_type chipset;
@@ -402,21 +272,38 @@
 void get_agp_version(struct agp_bridge_data *bridge);
 unsigned long agp_generic_mask_memory(unsigned long addr, int type);
 
+/* generic routines for agp>=3 */
+int agp3_generic_fetch_size(void);
+void agp3_generic_tlbflush(struct agp_memory *mem);
+int agp3_generic_configure(void);
+void agp3_generic_cleanup(void);
+
+/* aperture sizes have been standardised since v3 */
+#define AGP_GENERIC_SIZES_ENTRIES 11
+extern struct aper_size_info_16 agp3_generic_sizes[];
+
+
 extern int agp_off;
 extern int agp_try_unsupported_boot;
 
-/* Standard agp registers */
-#define AGPSTAT			0x4
-#define AGPCMD			0x8
-#define AGPNISTAT		0xc
-#define AGPCTRL                 0x10
-#define AGPNEPG			0x16
-#define AGPNICMD		0x20
+/* Chipset independant registers (from AGP Spec) */
+#define AGP_APBASE	0x10
+
+#define AGPSTAT		0x4
+#define AGPCMD		0x8
+#define AGPNISTAT	0xc
+#define AGPCTRL		0x10
+#define AGPAPSIZE	0x14
+#define AGPNEPG		0x16
+#define AGPGARTLO	0x18
+#define AGPGARTHI	0x1c
+#define AGPNICMD	0x20
 
 #define AGP_MAJOR_VERSION_SHIFT	(20)
 #define AGP_MINOR_VERSION_SHIFT	(16)
 
 #define AGPSTAT_RQ_DEPTH	(0xff000000)
+#define AGPSTAT_RQ_DEPTH_SHIFT	24
 
 #define AGPSTAT_CAL_MASK	(1<<12|1<<11|1<<10)
 #define AGPSTAT_ARQSZ		(1<<15|1<<14|1<<13)
@@ -435,4 +322,7 @@
 #define AGPSTAT3_8X		(1<<1)
 #define AGPSTAT3_4X		(1)
 
-#endif				/* _AGP_BACKEND_PRIV_H */
+#define AGPCTRL_APERENB		(1<<8)
+#define AGPCTRL_GTLBEN		(1<<7)
+
+#endif	/* _AGP_BACKEND_PRIV_H */
diff -Nru a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
--- a/drivers/char/agp/ali-agp.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/char/agp/ali-agp.c	Sat Apr  3 19:38:45 2004
@@ -9,6 +9,14 @@
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+#define ALI_AGPCTRL	0xb8
+#define ALI_ATTBASE	0xbc
+#define ALI_TLBCTRL	0xc0
+#define ALI_TAGCTRL	0xc4
+#define ALI_CACHE_FLUSH_CTRL	0xD0
+#define ALI_CACHE_FLUSH_ADDR_MASK	0xFFFFF000
+#define ALI_CACHE_FLUSH_EN	0x100
+
 static int ali_fetch_size(void)
 {
 	int i;
diff -Nru a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
--- a/drivers/char/agp/amd-k7-agp.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/char/agp/amd-k7-agp.c	Sat Apr  3 19:38:57 2004
@@ -11,6 +11,15 @@
 #include <linux/mm.h>
 #include "agp.h"
 
+#define AMD_MMBASE	0x14
+#define AMD_APSIZE	0xac
+#define AMD_MODECNTL	0xb0
+#define AMD_MODECNTL2	0xb2
+#define AMD_GARTENABLE	0x02	/* In mmio region (16-bit register) */
+#define AMD_ATTBASE	0x04	/* In mmio region (32-bit register) */
+#define AMD_TLBFLUSH	0x0c	/* In mmio region (32-bit register) */
+#define AMD_CACHEENTRY	0x10	/* In mmio region (32-bit register) */
+
 struct amd_page_map {
 	unsigned long *real;
 	unsigned long *remapped;
diff -Nru a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
--- a/drivers/char/agp/amd64-agp.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/char/agp/amd64-agp.c	Sat Apr  3 19:38:45 2004
@@ -31,6 +31,13 @@
 #define INVGART		(1<<0)
 #define GARTPTEERR	(1<<1)
 
+/* K8 On-cpu GART registers */
+#define AMD64_GARTAPERTURECTL	0x90
+#define AMD64_GARTAPERTUREBASE	0x94
+#define AMD64_GARTTABLEBASE	0x98
+#define AMD64_GARTCACHECTL	0x9c
+#define AMD64_GARTEN		(1<<0)
+
 /* NVIDIA K8 registers */
 #define NVIDIA_X86_64_0_APBASE		0x10
 #define NVIDIA_X86_64_1_APBASE1		0x50
@@ -382,8 +389,9 @@
 	case 0x11: revstring="B0"; break;
 	case 0x12: revstring="B1"; break;
 	case 0x13: revstring="B2"; break;
+	case 0x14: revstring="B3"; break;
 	default:   revstring="??"; break;
-		}
+	}
 
 	printk (KERN_INFO PFX "Detected AMD 8151 AGP Bridge rev %s\n", revstring);
 
diff -Nru a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
--- a/drivers/char/agp/ati-agp.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/char/agp/ati-agp.c	Sat Apr  3 19:38:54 2004
@@ -10,6 +10,18 @@
 #include <asm/agp.h>
 #include "agp.h"
 
+#define ATI_GART_MMBASE_ADDR	0x14
+#define ATI_RS100_APSIZE	0xac
+#define ATI_RS100_IG_AGPMODE	0xb0
+#define ATI_RS300_APSIZE	0xf8
+#define ATI_RS300_IG_AGPMODE	0xfc
+#define ATI_GART_FEATURE_ID		0x00
+#define ATI_GART_BASE			0x04
+#define ATI_GART_CACHE_SZBASE		0x08
+#define ATI_GART_CACHE_CNTRL		0x0c
+#define ATI_GART_CACHE_ENTRY_CNTRL	0x10
+
+
 static struct aper_size_info_lvl2 ati_generic_sizes[7] =
 {
 	{2048, 524288, 0x0000000c},
diff -Nru a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
--- a/drivers/char/agp/generic.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/agp/generic.c	Sat Apr  3 19:38:42 2004
@@ -880,7 +880,7 @@
 void *agp_generic_alloc_page(void)
 {
 	struct page * page;
-	
+
 	page = alloc_page(GFP_KERNEL);
 	if (page == NULL)
 		return 0;
@@ -955,4 +955,86 @@
 		return addr;
 }
 EXPORT_SYMBOL(agp_generic_mask_memory);
+
+/*
+ * These functions are implemented according to the AGPv3 spec,
+ * which covers implementation details that had previously been
+ * left open.
+ */
+
+int agp3_generic_fetch_size(void)
+{
+	u16 temp_size;
+	int i;
+	struct aper_size_info_16 *values;
+
+	pci_read_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, &temp_size);
+	values = A_SIZE_16(agp_bridge->driver->aperture_sizes);
+
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
+		if (temp_size == values[i].size_value) {
+			agp_bridge->previous_size =
+				agp_bridge->current_size = (void *) (values + i);
+
+			agp_bridge->aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(agp3_generic_fetch_size);
+
+void agp3_generic_tlbflush(struct agp_memory *mem)
+{
+	u32 ctrl;
+	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &ctrl);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl & ~AGPCTRL_GTLBEN);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl);
+}
+EXPORT_SYMBOL(agp3_generic_tlbflush);
+
+int agp3_generic_configure(void)
+{
+	u32 temp;
+	struct aper_size_info_16 *current_size;
+
+	current_size = A_SIZE_16(agp_bridge->current_size);
+
+	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
+	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+	/* set aperture size */
+	pci_write_config_word(agp_bridge->dev, agp_bridge->capndx+AGPAPSIZE, current_size->size_value);
+	/* set gart pointer */
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPGARTLO, agp_bridge->gatt_bus_addr);
+	/* enable aperture and GTLB */
+	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &temp);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, temp | AGPCTRL_APERENB | AGPCTRL_GTLBEN);
+	return 0;
+}
+EXPORT_SYMBOL(agp3_generic_configure);
+
+void agp3_generic_cleanup(void)
+{
+	u32 ctrl;
+	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, &ctrl);
+	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+AGPCTRL, ctrl & ~AGPCTRL_APERENB);
+}
+EXPORT_SYMBOL(agp3_generic_cleanup);
+
+struct aper_size_info_16 agp3_generic_sizes[AGP_GENERIC_SIZES_ENTRIES] =
+{
+	{4096, 1048576, 10,0x000},
+	{2048,  524288, 9, 0x800},
+	{1024,  262144, 8, 0xc00},
+	{ 512,  131072, 7, 0xe00},
+	{ 256,   65536, 6, 0xf00},
+	{ 128,   32768, 5, 0xf20},
+	{  64,   16384, 4, 0xf30},
+	{  32,    8192, 3, 0xf38},
+	{  16,    4096, 2, 0xf3c},
+	{   8,    2048, 1, 0xf3e},
+	{   4,    1024, 0, 0xf3f}
+};
+EXPORT_SYMBOL(agp3_generic_sizes);
 
diff -Nru a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
--- a/drivers/char/agp/hp-agp.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/agp/hp-agp.c	Sat Apr  3 19:38:55 2004
@@ -27,10 +27,6 @@
 #define HP_ZX1_TCNFG		0x318
 #define HP_ZX1_PDIR_BASE	0x320
 
-/* HP ZX1 LBA registers */
-#define HP_ZX1_AGP_STATUS	0x64
-#define HP_ZX1_AGP_COMMAND	0x68
-
 #define HP_ZX1_IOVA_BASE	GB(1UL)
 #define HP_ZX1_IOVA_SIZE	GB(1UL)
 #define HP_ZX1_GART_SIZE	(HP_ZX1_IOVA_SIZE / 2)
@@ -39,6 +35,9 @@
 #define HP_ZX1_PDIR_VALID_BIT	0x8000000000000000UL
 #define HP_ZX1_IOVA_TO_PDIR(va)	((va - hp_private.iova_base) >> hp_private.io_tlb_shift)
 
+#define AGP8X_MODE_BIT		3
+#define AGP8X_MODE		(1 << AGP8X_MODE_BIT)
+
 /* AGP bridge need not be PCI device, but DRM thinks it is. */
 static struct pci_dev fake_bridge_dev;
 
@@ -57,6 +56,7 @@
 static struct _hp_private {
 	volatile u8 *ioc_regs;
 	volatile u8 *lba_regs;
+	int lba_cap_offset;
 	u64 *io_pdir;		// PDIR for entire IOVA
 	u64 *gatt;		// PDIR just for GART (subset of above)
 	u64 gatt_entries;
@@ -109,6 +109,7 @@
 	hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
 
 	if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
+		/* Normal case when no AGP device in system */
 	    	hp->gatt = 0;
 		hp->gatt_entries = 0;
 		printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
@@ -156,12 +157,13 @@
 }
 
 static int __init
-hp_zx1_ioc_init (u64 ioc_hpa, u64 lba_hpa)
+hp_zx1_ioc_init (u64 hpa)
 {
 	struct _hp_private *hp = &hp_private;
 
-	hp->ioc_regs = ioremap(ioc_hpa, 1024);
-	hp->lba_regs = ioremap(lba_hpa, 256);
+	hp->ioc_regs = ioremap(hpa, 1024);
+	if (!hp->ioc_regs)
+		return -ENOMEM;
 
 	/*
 	 * If the IOTLB is currently disabled, we can take it over.
@@ -176,6 +178,51 @@
 }
 
 static int
+hp_zx1_lba_find_capability (volatile u8 *hpa, int cap)
+{
+	u16 status;
+	u8 pos, id;
+	int ttl = 48;
+
+	status = INREG16(hpa, PCI_STATUS);
+	if (!(status & PCI_STATUS_CAP_LIST))
+		return 0;
+	pos = INREG8(hpa, PCI_CAPABILITY_LIST);
+	while (ttl-- && pos >= 0x40) {
+		pos &= ~3;
+		id = INREG8(hpa, pos + PCI_CAP_LIST_ID);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+		pos = INREG8(hpa, pos + PCI_CAP_LIST_NEXT);
+	}
+	return 0;
+}
+
+static int __init
+hp_zx1_lba_init (u64 hpa)
+{
+	struct _hp_private *hp = &hp_private;
+	int cap;
+
+	hp->lba_regs = ioremap(hpa, 256);
+	if (!hp->lba_regs)
+		return -ENOMEM;
+
+	hp->lba_cap_offset = hp_zx1_lba_find_capability(hp->lba_regs, PCI_CAP_ID_AGP);
+
+	cap = INREG32(hp->lba_regs, hp->lba_cap_offset) & 0xff;
+	if (cap != PCI_CAP_ID_AGP) {
+		printk(KERN_ERR PFX "Invalid capability ID 0x%02x at 0x%x\n",
+		       cap, hp->lba_cap_offset);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int
 hp_zx1_fetch_size(void)
 {
 	int size;
@@ -192,13 +239,8 @@
 	struct _hp_private *hp = &hp_private;
 
 	agp_bridge->gart_bus_addr = hp->gart_base;
-#if 0
-	/* ouch!! can't do that with a non-PCI AGP bridge... */
-	agp_bridge->capndx = pci_find_capability(agp_bridge->dev, PCI_CAP_ID_AGP);
-#else
-	agp_bridge->capndx = 0;
-#endif
-	agp_bridge->mode = INREG32(hp->lba_regs, HP_ZX1_AGP_STATUS);
+	agp_bridge->capndx = hp->lba_cap_offset;
+	agp_bridge->mode = INREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_STATUS);
 
 	if (hp->io_pdir_owner) {
 		OUTREG64(hp->ioc_regs, HP_ZX1_PDIR_BASE, virt_to_phys(hp->io_pdir));
@@ -217,9 +259,13 @@
 {
 	struct _hp_private *hp = &hp_private;
 
-	if (hp->io_pdir_owner)
-		OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0);
-	iounmap((void *) hp->ioc_regs);
+	if (hp->ioc_regs) {
+		if (hp->io_pdir_owner)
+			OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0);
+		iounmap((void *) hp->ioc_regs);
+	}
+	if (hp->lba_regs)
+		iounmap((void *) hp->lba_regs);
 }
 
 static void
@@ -350,14 +396,14 @@
 	struct _hp_private *hp = &hp_private;
 	u32 command;
 
-	command = INREG32(hp->lba_regs, HP_ZX1_AGP_STATUS);
+	command = INREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_STATUS);
 
 	command = agp_collect_device_status(mode, command);
 	command |= 0x00000100;
 
-	OUTREG32(hp->lba_regs, HP_ZX1_AGP_COMMAND, command);
+	OUTREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_COMMAND, command);
 
-	agp_device_command(command, 0);
+	agp_device_command(command, (mode & AGP8X_MODE) != 0);
 }
 
 struct agp_bridge_driver hp_zx1_driver = {
@@ -386,22 +432,32 @@
 hp_zx1_setup (u64 ioc_hpa, u64 lba_hpa)
 {
 	struct agp_bridge_data *bridge;
-	int error;
+	int error = 0;
+
+	error = hp_zx1_ioc_init(ioc_hpa);
+	if (error)
+		goto fail;
 
-	error = hp_zx1_ioc_init(ioc_hpa, lba_hpa);
+	error = hp_zx1_lba_init(lba_hpa);
 	if (error)
-		return error;
+		goto fail;
 
 	bridge = agp_alloc_bridge();
-	if (!bridge)
-		return -ENOMEM;
+	if (!bridge) {
+		error = -ENOMEM;
+		goto fail;
+	}
 	bridge->driver = &hp_zx1_driver;
 
 	fake_bridge_dev.vendor = PCI_VENDOR_ID_HP;
 	fake_bridge_dev.device = PCI_DEVICE_ID_HP_PCIX_LBA;
 	bridge->dev = &fake_bridge_dev;
 
-	return agp_add_bridge(bridge);
+	error = agp_add_bridge(bridge);
+  fail:
+	if (error)
+		hp_zx1_cleanup();
+	return error;
 }
 
 static acpi_status __init
@@ -416,7 +472,7 @@
 
 	status = hp_acpi_csr_space(obj, &lba_hpa, &length);
 	if (ACPI_FAILURE(status))
-		return AE_OK;
+		return AE_OK; /* keep looking for another bridge */
 
 	/* Look for an enclosing IOC scope and find its CSR space */
 	handle = obj;
@@ -452,7 +508,7 @@
 		(char *) context, sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);
 
 	hp_zx1_gart_found = 1;
-	return AE_CTRL_TERMINATE;
+	return AE_CTRL_TERMINATE; /* we only support one bridge; quit looking */
 }
 
 static int __init
diff -Nru a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
--- a/drivers/char/agp/i460-agp.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/char/agp/i460-agp.c	Sat Apr  3 19:38:44 2004
@@ -14,6 +14,13 @@
 
 #include "agp.h"
 
+#define INTEL_I460_BAPBASE		0x98
+#define INTEL_I460_GXBCTL		0xa0
+#define INTEL_I460_AGPSIZ		0xa2
+#define INTEL_I460_ATTBASE		0xfe200000
+#define INTEL_I460_GATT_VALID		(1UL << 24)
+#define INTEL_I460_GATT_COHERENT	(1UL << 25)
+
 /*
  * The i460 can operate with large (4MB) pages, but there is no sane way to support this
  * within the current kernel/DRM environment, so we disable the relevant code for now.
diff -Nru a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
--- a/drivers/char/agp/intel-agp.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/char/agp/intel-agp.c	Sat Apr  3 19:38:43 2004
@@ -13,6 +13,31 @@
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+/* Intel 815 register */
+#define INTEL_815_APCONT	0x51
+#define INTEL_815_ATTBASE_MASK	~0x1FFFFFFF
+
+/* Intel i820 registers */
+#define INTEL_I820_RDCR		0x51
+#define INTEL_I820_ERRSTS	0xc8
+
+/* Intel i840 registers */
+#define INTEL_I840_MCHCFG	0x50
+#define INTEL_I840_ERRSTS	0xc8
+
+/* Intel i850 registers */
+#define INTEL_I850_MCHCFG	0x50
+#define INTEL_I850_ERRSTS	0xc8
+
+/* Intel 7505 registers */
+#define INTEL_I7505_APSIZE	0x74
+#define INTEL_I7505_NCAPID	0x60
+#define INTEL_I7505_NISTAT	0x6c
+#define INTEL_I7505_ATTBASE	0x78
+#define INTEL_I7505_ERRSTS	0x42
+#define INTEL_I7505_AGPCTRL	0x70
+#define INTEL_I7505_MCHCFG	0x50
+
 static struct aper_size_info_fixed intel_i810_sizes[] =
 {
 	{64, 16384, 4},
@@ -942,7 +967,7 @@
 	{32, 8192, 3, 56}
 };
 
-struct agp_bridge_driver intel_generic_driver = {
+static struct agp_bridge_driver intel_generic_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_generic_sizes,
 	.size_type		= U16_APER_SIZE,
@@ -965,7 +990,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver intel_810_driver = {
+static struct agp_bridge_driver intel_810_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_i810_sizes,
 	.size_type		= FIXED_APER_SIZE,
@@ -989,8 +1014,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-
-struct agp_bridge_driver intel_815_driver = {
+static struct agp_bridge_driver intel_815_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_815_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -1013,7 +1037,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver intel_830_driver = {
+static struct agp_bridge_driver intel_830_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_i830_sizes,
 	.size_type		= FIXED_APER_SIZE,
@@ -1037,8 +1061,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-
-struct agp_bridge_driver intel_820_driver = {
+static struct agp_bridge_driver intel_820_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_8xx_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -1061,7 +1084,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver intel_830mp_driver = {
+static struct agp_bridge_driver intel_830mp_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_830mp_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -1084,7 +1107,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver intel_840_driver = {
+static struct agp_bridge_driver intel_840_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_8xx_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -1107,7 +1130,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver intel_845_driver = {
+static struct agp_bridge_driver intel_845_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_8xx_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -1130,7 +1153,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver intel_850_driver = {
+static struct agp_bridge_driver intel_850_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_8xx_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -1153,7 +1176,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver intel_860_driver = {
+static struct agp_bridge_driver intel_860_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_8xx_sizes,
 	.size_type		= U8_APER_SIZE,
@@ -1176,7 +1199,7 @@
 	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-struct agp_bridge_driver intel_7505_driver = {
+static struct agp_bridge_driver intel_7505_driver = {
 	.owner			= THIS_MODULE,
 	.aperture_sizes		= intel_8xx_sizes,
 	.size_type		= U8_APER_SIZE,
diff -Nru a/drivers/char/agp/intel-mch-agp.c b/drivers/char/agp/intel-mch-agp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/agp/intel-mch-agp.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,631 @@
+/*
+ * Intel MCH AGPGART routines.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include "agp.h"
+
+
+#define AGP_DCACHE_MEMORY	1
+#define AGP_PHYS_MEMORY		2
+
+static struct gatt_mask intel_i810_masks[] =
+{
+	{.mask = I810_PTE_VALID, .type = 0},
+	{.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
+	{.mask = I810_PTE_VALID, .type = 0}
+};
+
+static void intel_i810_tlbflush(struct agp_memory *mem)
+{
+	return;
+}
+
+static void intel_i810_agp_enable(u32 mode)
+{
+	return;
+}
+
+
+/*
+ * The i810/i830 requires a physical address to program its mouse
+ * pointer into hardware.
+ * However the Xserver still writes to it through the agp aperture.
+ */
+static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
+{
+	struct agp_memory *new;
+	void *addr;
+
+	if (pg_count != 1)
+		return NULL;
+
+	addr = agp_bridge->driver->agp_alloc_page();
+	if (addr == NULL)
+		return NULL;
+
+	new = agp_create_memory(1);
+	if (new == NULL)
+		return NULL;
+
+	new->memory[0] = agp_bridge->driver->mask_memory(virt_to_phys(addr), type);
+	new->page_count = 1;
+	new->num_scratch_pages = 1;
+	new->type = AGP_PHYS_MEMORY;
+	new->physical = new->memory[0];
+	return new;
+}
+
+static void intel_i810_free_by_type(struct agp_memory *curr)
+{
+	agp_free_key(curr->key);
+	if(curr->type == AGP_PHYS_MEMORY) {
+		agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[0]));
+		vfree(curr->memory);
+	}
+	kfree(curr);
+}
+
+static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
+{
+	/* Type checking must be done elsewhere */
+	return addr | agp_bridge->driver->masks[type].mask;
+}
+
+static struct aper_size_info_fixed intel_i830_sizes[] =
+{
+	{128, 32768, 5},
+	/* The 64M mode still requires a 128k gatt */
+	{64, 16384, 5}
+};
+
+static struct _intel_i830_private {
+	struct pci_dev *i830_dev;		/* device one */
+	volatile u8 *registers;
+	int gtt_entries;
+} intel_i830_private;
+
+static void intel_i830_init_gtt_entries(void)
+{
+	u16 gmch_ctrl;
+	int gtt_entries;
+	u8 rdct;
+	int local = 0;
+	static const int ddt[4] = { 0, 16, 32, 64 };
+
+	pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+
+	if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
+	    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
+		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+		case I830_GMCH_GMS_STOLEN_512:
+			gtt_entries = KB(512) - KB(132);
+			break;
+		case I830_GMCH_GMS_STOLEN_1024:
+			gtt_entries = MB(1) - KB(132);
+			break;
+		case I830_GMCH_GMS_STOLEN_8192:
+			gtt_entries = MB(8) - KB(132);
+			break;
+		case I830_GMCH_GMS_LOCAL:
+			rdct = INREG8(intel_i830_private.registers,
+				      I830_RDRAM_CHANNEL_TYPE);
+			gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
+					MB(ddt[I830_RDRAM_DDT(rdct)]);
+			local = 1;
+			break;
+		default:
+			gtt_entries = 0;
+			break;
+		}
+	} else {
+		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+		case I855_GMCH_GMS_STOLEN_1M:
+			gtt_entries = MB(1) - KB(132);
+			break;
+		case I855_GMCH_GMS_STOLEN_4M:
+			gtt_entries = MB(4) - KB(132);
+			break;
+		case I855_GMCH_GMS_STOLEN_8M:
+			gtt_entries = MB(8) - KB(132);
+			break;
+		case I855_GMCH_GMS_STOLEN_16M:
+			gtt_entries = MB(16) - KB(132);
+			break;
+		case I855_GMCH_GMS_STOLEN_32M:
+			gtt_entries = MB(32) - KB(132);
+			break;
+		default:
+			gtt_entries = 0;
+			break;
+		}
+	}
+	if (gtt_entries > 0)
+		printk(KERN_INFO PFX "Detected %dK %s memory.\n",
+		       gtt_entries / KB(1), local ? "local" : "stolen");
+	else
+		printk(KERN_INFO PFX
+		       "No pre-allocated video memory detected.\n");
+	gtt_entries /= KB(4);
+
+	intel_i830_private.gtt_entries = gtt_entries;
+}
+
+/* The intel i830 automatically initializes the agp aperture during POST.
+ * Use the memory already set aside for in the GTT.
+ */
+static int intel_i830_create_gatt_table(void)
+{
+	int page_order;
+	struct aper_size_info_fixed *size;
+	int num_entries;
+	u32 temp;
+
+	size = agp_bridge->current_size;
+	page_order = size->page_order;
+	num_entries = size->num_entries;
+	agp_bridge->gatt_table_real = 0;
+
+	pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp);
+	temp &= 0xfff80000;
+
+	intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096);
+	if (!intel_i830_private.registers)
+		return (-ENOMEM);
+
+	temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000;
+	global_cache_flush();
+
+	/* we have to call this as early as possible after the MMIO base address is known */
+	intel_i830_init_gtt_entries();
+
+	agp_bridge->gatt_table = NULL;
+
+	agp_bridge->gatt_bus_addr = temp;
+
+	return(0);
+}
+
+/* Return the gatt table to a sane state. Use the top of stolen
+ * memory for the GTT.
+ */
+static int intel_i830_free_gatt_table(void)
+{
+	return(0);
+}
+
+static int intel_i830_fetch_size(void)
+{
+	u16 gmch_ctrl;
+	struct aper_size_info_fixed *values;
+
+	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+
+	if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
+	    agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
+		/* 855GM/852GM/865G has 128MB aperture size */
+		agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
+		agp_bridge->aperture_size_idx = 0;
+		return(values[0].size);
+	}
+
+	pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+
+	if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
+		agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
+		agp_bridge->aperture_size_idx = 0;
+		return(values[0].size);
+	} else {
+		agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
+		agp_bridge->aperture_size_idx = 1;
+		return(values[1].size);
+	}
+
+	return(0);
+}
+
+static int intel_i830_configure(void)
+{
+	struct aper_size_info_fixed *current_size;
+	u32 temp;
+	u16 gmch_ctrl;
+	int i;
+
+	current_size = A_SIZE_FIX(agp_bridge->current_size);
+
+	pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp);
+	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+	pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl);
+	gmch_ctrl |= I830_GMCH_ENABLED;
+	pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl);
+
+	OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED);
+	global_cache_flush();
+
+	if (agp_bridge->driver->needs_scratch_page)
+		for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
+			OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page);
+
+	return (0);
+}
+
+static void intel_i830_cleanup(void)
+{
+	iounmap((void *) intel_i830_private.registers);
+}
+
+static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start,
+				int type)
+{
+	int i,j,num_entries;
+	void *temp;
+
+	temp = agp_bridge->current_size;
+	num_entries = A_SIZE_FIX(temp)->num_entries;
+
+	if (pg_start < intel_i830_private.gtt_entries) {
+		printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n",
+				pg_start,intel_i830_private.gtt_entries);
+
+		printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n");
+		return (-EINVAL);
+	}
+
+	if ((pg_start + mem->page_count) > num_entries)
+		return (-EINVAL);
+
+	/* The i830 can't check the GTT for entries since its read only,
+	 * depend on the caller to make the correct offset decisions.
+	 */
+
+	if ((type != 0 && type != AGP_PHYS_MEMORY) ||
+		(mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
+		return (-EINVAL);
+
+	global_cache_flush();
+
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
+		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),
+			agp_bridge->driver->mask_memory(mem->memory[i], mem->type));
+
+	global_cache_flush();
+
+	agp_bridge->driver->tlb_flush(mem);
+
+	return(0);
+}
+
+static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start,
+				int type)
+{
+	int i;
+
+	global_cache_flush();
+
+	if (pg_start < intel_i830_private.gtt_entries) {
+		printk (KERN_INFO PFX "Trying to disable local/stolen memory\n");
+		return (-EINVAL);
+	}
+
+	for (i = pg_start; i < (mem->page_count + pg_start); i++)
+		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page);
+
+	global_cache_flush();
+
+	agp_bridge->driver->tlb_flush(mem);
+
+	return (0);
+}
+
+static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
+{
+	if (type == AGP_PHYS_MEMORY)
+		return(alloc_agpphysmem_i8xx(pg_count, type));
+
+	/* always return NULL for other allocation types for now */
+	return(NULL);
+}
+
+static int intel_8xx_fetch_size(void)
+{
+	u8 temp;
+	int i;
+	struct aper_size_info_8 *values;
+
+	pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
+
+	values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
+
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
+		if (temp == values[i].size_value) {
+			agp_bridge->previous_size =
+				agp_bridge->current_size = (void *) (values + i);
+			agp_bridge->aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+	return 0;
+}
+
+static void intel_8xx_tlbflush(struct agp_memory *mem)
+{
+	u32 temp;
+	pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
+	pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp & ~(1 << 7));
+	pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
+	pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp | (1 << 7));
+}
+
+static void intel_8xx_cleanup(void)
+{
+	u16 temp;
+	struct aper_size_info_8 *previous_size;
+
+	previous_size = A_SIZE_8(agp_bridge->previous_size);
+	pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
+	pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
+	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value);
+}
+
+static int intel_845_configure(void)
+{
+	u32 temp;
+	u8 temp2;
+	struct aper_size_info_8 *current_size;
+
+	current_size = A_SIZE_8(agp_bridge->current_size);
+
+	/* aperture size */
+	pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value); 
+
+	/* address to map to */
+	pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
+	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+	/* attbase - aperture base */
+	pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr); 
+
+	/* agpctrl */
+	pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000); 
+
+	/* agpm */
+	pci_read_config_byte(agp_bridge->dev, INTEL_I845_AGPM, &temp2);
+	pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1));
+	/* clear any possible error conditions */
+	pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); 
+	return 0;
+}
+
+
+/* Setup function */
+static struct gatt_mask intel_generic_masks[] =
+{
+	{.mask = 0x00000017, .type = 0}
+};
+
+static struct aper_size_info_8 intel_8xx_sizes[7] =
+{
+	{256, 65536, 6, 0},
+	{128, 32768, 5, 32},
+	{64, 16384, 4, 48},
+	{32, 8192, 3, 56},
+	{16, 4096, 2, 60},
+	{8, 2048, 1, 62},
+	{4, 1024, 0, 63}
+};
+
+static struct agp_bridge_driver intel_830_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_i830_sizes,
+	.size_type		= FIXED_APER_SIZE,
+	.num_aperture_sizes 	= 2,
+	.needs_scratch_page	= TRUE,
+	.configure		= intel_i830_configure,
+	.fetch_size		= intel_i830_fetch_size,
+	.cleanup		= intel_i830_cleanup,
+	.tlb_flush		= intel_i810_tlbflush,
+	.mask_memory		= intel_i810_mask_memory,
+	.masks			= intel_i810_masks,
+	.agp_enable		= intel_i810_agp_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= intel_i830_create_gatt_table,
+	.free_gatt_table	= intel_i830_free_gatt_table,
+	.insert_memory		= intel_i830_insert_entries,
+	.remove_memory		= intel_i830_remove_entries,
+	.alloc_by_type		= intel_i830_alloc_by_type,
+	.free_by_type		= intel_i810_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
+
+static struct agp_bridge_driver intel_845_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_8xx_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= intel_845_configure,
+	.fetch_size		= intel_8xx_fetch_size,
+	.cleanup		= intel_8xx_cleanup,
+	.tlb_flush		= intel_8xx_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
+
+
+static int find_i830(u16 device)
+{
+	struct pci_dev *i830_dev;
+
+	i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL);
+	if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) {
+		i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+				device, i830_dev);
+	}
+
+	if (!i830_dev)
+		return 0;
+
+	intel_i830_private.i830_dev = i830_dev;
+	return 1;
+}
+
+static int __devinit agp_intelmch_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	struct agp_bridge_data *bridge;
+	char *name = "(unknown)";
+	u8 cap_ptr = 0;
+	struct resource *r;
+
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_INTEL_82865_HB:
+		if (find_i830(PCI_DEVICE_ID_INTEL_82865_IG)) {
+			bridge->driver = &intel_830_driver;
+		} else {
+			bridge->driver = &intel_845_driver;
+		}
+		name = "865";
+		break;
+	case PCI_DEVICE_ID_INTEL_82875_HB:
+		bridge->driver = &intel_845_driver;
+		name = "i875";
+		break;
+
+	default:
+		printk(KERN_ERR PFX "Unsupported Intel chipset (device id: %04x)\n",
+			    pdev->device);
+		return -ENODEV;
+	};
+
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
+
+	if (bridge->driver == &intel_830_driver)
+		bridge->dev_private_data = &intel_i830_private;
+
+	printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", name);
+
+	/*
+	* The following fixes the case where the BIOS has "forgotten" to
+	* provide an address range for the GART.
+	* 20030610 - hamish@zot.org
+	*/
+	r = &pdev->resource[0];
+	if (!r->start && r->end) {
+		if(pci_assign_resource(pdev, 0)) {
+			printk(KERN_ERR PFX "could not assign resource 0\n");
+			return (-ENODEV);
+		}
+	}
+
+	/*
+	* If the device has not been properly setup, the following will catch
+	* the problem and should stop the system from crashing.
+	* 20030610 - hamish@zot.org
+	*/
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR PFX "Unable to Enable PCI device\n");
+		return (-ENODEV);
+	}
+
+	/* Fill in the mode register */
+	if (cap_ptr) {
+		pci_read_config_dword(pdev,
+				bridge->capndx+PCI_AGP_STATUS,
+				&bridge->mode);
+	}
+
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+}
+
+static void __devexit agp_intelmch_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
+}
+
+static int agp_intelmch_suspend(struct pci_dev *dev, u32 state)
+{
+	return 0;
+}
+
+static int agp_intelmch_resume(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	if (bridge->driver == &intel_845_driver)
+		intel_845_configure();
+
+	return 0;
+}
+
+static struct pci_device_id agp_intelmch_pci_table[] = {
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_INTEL,
+	.device		= PCI_ANY_ID,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, agp_intelmch_pci_table);
+
+static struct pci_driver agp_intelmch_pci_driver = {
+	.name		= "agpgart-intel-mch",
+	.id_table	= agp_intelmch_pci_table,
+	.probe		= agp_intelmch_probe,
+	.remove		= agp_intelmch_remove,
+	.suspend	= agp_intelmch_suspend,
+	.resume		= agp_intelmch_resume,
+};
+
+/* intel_agp_init() must not be declared static for explicit
+   early initialization to work (ie i810fb) */
+int __init agp_intelmch_init(void)
+{
+	static int agp_initialised=0;
+
+	if (agp_initialised == 1)
+		return 0;
+	agp_initialised=1;
+
+	return pci_module_init(&agp_intelmch_pci_driver);
+}
+
+static void __exit agp_intelmch_cleanup(void)
+{
+	pci_unregister_driver(&agp_intelmch_pci_driver);
+}
+
+module_init(agp_intelmch_init);
+module_exit(agp_intelmch_cleanup);
+
+MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
+MODULE_LICENSE("GPL and additional rights");
+
diff -Nru a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
--- a/drivers/char/agp/nvidia-agp.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/agp/nvidia-agp.c	Sat Apr  3 19:38:41 2004
@@ -13,6 +13,17 @@
 #include <linux/mm.h>
 #include "agp.h"
 
+/* NVIDIA registers */
+#define NVIDIA_0_APSIZE		0x80
+#define NVIDIA_1_WBC		0xf0
+#define NVIDIA_2_GARTCTRL	0xd0
+#define NVIDIA_2_APBASE		0xd8
+#define NVIDIA_2_APLIMIT	0xdc
+#define NVIDIA_2_ATTBASE(i)	(0xe0 + (i) * 4)
+#define NVIDIA_3_APBASE		0x50
+#define NVIDIA_3_APLIMIT	0x54
+
+
 static struct _nvidia_private {
 	struct pci_dev *dev_1;
 	struct pci_dev *dev_2;
diff -Nru a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
--- a/drivers/char/agp/sis-agp.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/agp/sis-agp.c	Sat Apr  3 19:38:41 2004
@@ -8,6 +8,12 @@
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+#define SIS_ATTBASE	0x90
+#define SIS_APSIZE	0x94
+#define SIS_TLBCNTRL	0x97
+#define SIS_TLBFLUSH	0x98
+
+
 static int sis_fetch_size(void)
 {
 	u8 temp_size;
@@ -61,6 +67,42 @@
 			      (previous_size->size_value & ~(0x03)));
 }
 
+static void sis_648_enable(u32 mode)
+{
+	struct pci_dev *device = NULL;
+	u32 command;
+	int rate;
+
+	printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n",
+		agp_bridge->major_version,
+		agp_bridge->minor_version,
+		agp_bridge->dev->slot_name);
+
+	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_STATUS, &command);
+	command = agp_collect_device_status(mode, command);
+	command |= AGPSTAT_AGP_ENABLE;
+	rate = (command & 0x7) << 2;
+
+	while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) {
+		u8 agp = pci_find_capability(device, PCI_CAP_ID_AGP);
+		if (!agp)
+			continue;
+
+		printk(KERN_INFO PFX "Putting AGP V3 device at %s into %dx mode\n",
+			pci_name(device), rate);
+
+		pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command);
+
+		if(device->device == PCI_DEVICE_ID_SI_648) {
+			// weird: on 648 and 648fx chipsets any rate change in the target command register
+			// triggers a 5ms screwup during which the master cannot be configured
+			printk(KERN_INFO PFX "sis 648 agp fix - giving bridge time to recover\n");
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout (1+(HZ*10)/1000);
+		}
+	}
+}
+
 static struct aper_size_info_8 sis_generic_sizes[7] =
 {
 	{256, 65536, 6, 99},
@@ -176,6 +218,26 @@
 	{ }, /* dummy final entry, always present */
 };
 
+
+static void __devinit sis_get_driver(struct agp_bridge_data *bridge)
+{
+	if (bridge->dev->device == PCI_DEVICE_ID_SI_648) {
+		if (agp_bridge->major_version == 3 && agp_bridge->minor_version < 5) {
+			sis_driver.agp_enable=sis_648_enable;
+		} else {
+			sis_driver.agp_enable			= sis_648_enable;
+			sis_driver.aperture_sizes		= agp3_generic_sizes;
+			sis_driver.size_type			= U16_APER_SIZE;
+			sis_driver.num_aperture_sizes	= AGP_GENERIC_SIZES_ENTRIES;
+			sis_driver.configure			= agp3_generic_configure;
+			sis_driver.fetch_size			= agp3_generic_fetch_size;
+			sis_driver.cleanup				= agp3_generic_cleanup;
+			sis_driver.tlb_flush			= agp3_generic_tlbflush;
+		}
+	}
+}
+
+
 static int __devinit agp_sis_probe(struct pci_dev *pdev,
 				   const struct pci_device_id *ent)
 {
@@ -210,10 +272,11 @@
 	bridge->dev = pdev;
 	bridge->capndx = cap_ptr;
 
+	get_agp_version(bridge);
+
 	/* Fill in the mode register */
-	pci_read_config_dword(pdev,
-			bridge->capndx+PCI_AGP_STATUS,
-			&bridge->mode);
+	pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode);
+	sis_get_driver(bridge);
 
 	pci_set_drvdata(pdev, bridge);
 	return agp_add_bridge(bridge);
diff -Nru a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
--- a/drivers/char/agp/sworks-agp.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/agp/sworks-agp.c	Sat Apr  3 19:38:42 2004
@@ -8,6 +8,23 @@
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+#define SVWRKS_COMMAND		0x04
+#define SVWRKS_APSIZE		0x10
+#define SVWRKS_MMBASE		0x14
+#define SVWRKS_CACHING		0x4b
+#define SVWRKS_AGP_ENABLE	0x60
+#define SVWRKS_FEATURE		0x68
+
+#define SVWRKS_SIZE_MASK	0xfe000000
+
+/* Memory mapped registers */
+#define SVWRKS_GART_CACHE	0x02
+#define SVWRKS_GATTBASE		0x04
+#define SVWRKS_TLBFLUSH		0x10
+#define SVWRKS_POSTFLUSH	0x14
+#define SVWRKS_DIRFLUSH		0x0c
+
+
 struct serverworks_page_map {
 	unsigned long *real;
 	unsigned long *remapped;
@@ -454,10 +471,17 @@
 	}
 
 	switch (pdev->device) {
+	case 0x0006:
+		/* ServerWorks CNB20HE
+		Fail silently.*/
+		printk (KERN_ERR PFX "Detected ServerWorks CNB20HE chipset: No AGP present.\n");
+		return -ENODEV;
+
 	case PCI_DEVICE_ID_SERVERWORKS_HE:
 	case PCI_DEVICE_ID_SERVERWORKS_LE:
 	case 0x0007:
 		break;
+
 	default:
 		printk(KERN_ERR PFX "Unsupported Serverworks chipset "
 				"(device id: %04x)\n", pdev->device);
diff -Nru a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
--- a/drivers/char/agp/via-agp.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/agp/via-agp.c	Sat Apr  3 19:38:55 2004
@@ -9,6 +9,15 @@
 #include <linux/agp_backend.h>
 #include "agp.h"
 
+#define VIA_GARTCTRL	0x80
+#define VIA_APSIZE	0x84
+#define VIA_ATTBASE	0x88
+
+#define VIA_AGP3_GARTCTRL	0x90
+#define VIA_AGP3_APSIZE		0x94
+#define VIA_AGP3_ATTBASE	0x98
+#define VIA_AGPSEL		0xfd
+
 static int via_fetch_size(void)
 {
 	int i;
diff -Nru a/drivers/char/applicom.c b/drivers/char/applicom.c
--- a/drivers/char/applicom.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/applicom.c	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c
--- a/drivers/char/cyclades.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/cyclades.c	Sat Apr  3 19:38:42 2004
@@ -2679,7 +2679,8 @@
   struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
   unsigned char *base_addr;
   int card,chip,channel,index;
-  unsigned long orig_jiffies, char_time;
+  unsigned long orig_jiffies;
+  signed long char_time;
 	
     if (serial_paranoia_check(info, tty->name, "cy_wait_until_sent"))
 	return;
@@ -2699,7 +2700,7 @@
      */
     char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
     char_time = char_time / 5;
-    if (char_time == 0)
+    if (char_time <= 0)
 	char_time = 1;
     if (timeout < 0)
 	timeout = 0;
diff -Nru a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h
--- a/drivers/char/drm/drm_memory_debug.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/drm/drm_memory_debug.h	Sat Apr  3 19:38:41 2004
@@ -385,7 +385,7 @@
 	if (!handle) {
 		DRM_MEM_ERROR(DRM_MEM_TOTALAGP,
 			      "Attempt to free NULL AGP handle\n");
-		return retval;;
+		return retval;
 	}
 
 	if (DRM(agp_free_memory)(handle)) {
diff -Nru a/drivers/char/drm/drm_stub.h b/drivers/char/drm/drm_stub.h
--- a/drivers/char/drm/drm_stub.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/drm/drm_stub.h	Sat Apr  3 19:38:55 2004
@@ -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 @@
 			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 @@
 	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 @@
 			  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 @@
 		       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 @@
 		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 -Nru a/drivers/char/drm/gamma_context.h b/drivers/char/drm/gamma_context.h
--- a/drivers/char/drm/gamma_context.h	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/drm/gamma_context.h	Sat Apr  3 19:38:42 2004
@@ -84,7 +84,7 @@
 	}
 
 	wake_up_interruptible(&dev->buf_writers);
-	return DRM_MIN(avail, count);;
+	return DRM_MIN(avail, count);
 }
 
 
diff -Nru a/drivers/char/dz.c b/drivers/char/dz.c
--- a/drivers/char/dz.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/dz.c	Sat Apr  3 19:38:41 2004
@@ -431,7 +431,7 @@
 static void do_serial_hangup (void *private_data)
 {
 	struct dz_serial *info = (struct dz_serial *) private_data;
-	struct tty_struct *tty = info->tty;;
+	struct tty_struct *tty = info->tty;
         
 	if (!tty)
 		return;
diff -Nru a/drivers/char/efirtc.c b/drivers/char/efirtc.c
--- a/drivers/char/efirtc.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/char/efirtc.c	Sat Apr  3 19:38:54 2004
@@ -6,13 +6,13 @@
  *
  * Based on skeleton from the drivers/char/rtc.c driver by P. Gortmaker
  *
- * This code provides a architected & portable interface to the real time 
+ * This code provides an architected & portable interface to the real time
  * clock by using EFI instead of direct bit fiddling. The functionalities are 
  * quite different from the rtc.c driver. The only way to talk to the device 
  * is by using ioctl(). There is a /proc interface which provides the raw 
  * information.
  *
- * Please note that we have kept the API as close as possible from the 
+ * Please note that we have kept the API as close as possible to the
  * legacy RTC. The standard /sbin/hwclock program should work normally 
  * when used to get/set the time.
  *
@@ -297,7 +297,7 @@
 };
 
 /*
- *	We export RAW EFI information to /proc/efirtc
+ *	We export RAW EFI information to /proc/driver/efirtc
  */
 static int
 efi_rtc_get_status(char *buf)
@@ -307,6 +307,10 @@
 	char		*p = buf;
 	efi_bool_t	enabled, pending;	
 	unsigned long	flags;
+
+	memset(&eft, 0, sizeof(eft));
+	memset(&alm, 0, sizeof(alm));
+	memset(&cap, 0, sizeof(cap));
 
 	spin_lock_irqsave(&efi_rtc_lock, flags);
 
diff -Nru a/drivers/char/ftape/compressor/lzrw3.c b/drivers/char/ftape/compressor/lzrw3.c
--- a/drivers/char/ftape/compressor/lzrw3.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/ftape/compressor/lzrw3.c	Sat Apr  3 19:38:41 2004
@@ -701,7 +701,7 @@
           /* been postponed for lack of bytes.                                */
           if (literals>0)
             {
-             register UBYTE *r=p_ziv-literals;;
+             register UBYTE *r=p_ziv-literals;
              hash[HASH(r)]=r;
              if (literals==2)
                 {r++; hash[HASH(r)]=r;}
diff -Nru a/drivers/char/genrtc.c b/drivers/char/genrtc.c
--- a/drivers/char/genrtc.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/genrtc.c	Sat Apr  3 19:38:55 2004
@@ -466,6 +466,17 @@
 	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 @@
 	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 -Nru a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
--- a/drivers/char/hvc_console.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/hvc_console.c	Sat Apr  3 19:38:55 2004
@@ -131,31 +131,65 @@
 		     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 -Nru a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
--- a/drivers/char/ip2/i2lib.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/char/ip2/i2lib.c	Sat Apr  3 19:38:56 2004
@@ -1249,7 +1249,7 @@
 
 	}
 	if ( old_flags & STOPFL_FLAG ) {
-		if ( 1 == i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL) > 0 ) {
+		if (1 == i2QueueCommands(PTYPE_INLINE, pCh, 0, 1, CMD_STOPFL)) {
 			old_flags = 0;	// Success - clear flags
 		}
 
diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c
--- a/drivers/char/lp.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/char/lp.c	Sat Apr  3 19:38:40 2004
@@ -869,7 +869,7 @@
 
 int __init lp_init (void)
 {
-	int i;
+	int i, err = 0;
 
 	if (parport_nr[0] == LP_PARPORT_OFF)
 		return 0;
@@ -900,10 +900,15 @@
 
 	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 @@
 	}
 
 	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 -Nru a/drivers/char/mem.c b/drivers/char/mem.c
--- a/drivers/char/mem.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/char/mem.c	Sat Apr  3 19:38:43 2004
@@ -102,10 +102,11 @@
 }
 #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 +121,14 @@
 		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,7 +178,7 @@
 
 	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)
@@ -275,15 +282,19 @@
 	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 +303,21 @@
 	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) {
+					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 -Nru a/drivers/char/misc.c b/drivers/char/misc.c
--- a/drivers/char/misc.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/misc.c	Sat Apr  3 19:38:55 2004
@@ -342,6 +342,7 @@
 	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 -Nru a/drivers/char/mwave/smapi.c b/drivers/char/mwave/smapi.c
--- a/drivers/char/mwave/smapi.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/mwave/smapi.c	Sat Apr  3 19:38:55 2004
@@ -447,7 +447,7 @@
 	if (bRC) goto exit_smapi_request_error;
 
 	if (mwave_3780i_io) {
-		usDI = dspio_index;;
+		usDI = dspio_index;
 	}
 	if (mwave_3780i_irq) {
 		usSI = (usSI & 0xff00) | mwave_3780i_irq;
diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
--- a/drivers/char/pcmcia/synclink_cs.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/pcmcia/synclink_cs.c	Sat Apr  3 19:38:42 2004
@@ -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_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 @@
 	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 @@
 
 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 -Nru a/drivers/char/qtronix.c b/drivers/char/qtronix.c
--- a/drivers/char/qtronix.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/qtronix.c	Sat Apr  3 19:38:42 2004
@@ -206,7 +206,7 @@
 	unsigned char int_status;
 
 	cir = (struct cir_port *)dev_id;
-	int_status = get_int_status(cir);;
+	int_status = get_int_status(cir);
 	if (int_status & 0x4) {
 		clear_fifo(cir);
 		return;
diff -Nru a/drivers/char/random.c b/drivers/char/random.c
--- a/drivers/char/random.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/random.c	Sat Apr  3 19:38:41 2004
@@ -1640,9 +1640,8 @@
 	/*
 	 * If we gave the user some bytes, update the access time.
 	 */
-	if (count != 0) {
-		update_atime(file->f_dentry->d_inode);
-	}
+	if (count)
+		file_accessed(file);
 	
 	return (count ? count : retval);
 }
diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/char/raw.c	Sat Apr  3 19:38:44 2004
@@ -17,6 +17,7 @@
 #include <linux/raw.h>
 #include <linux/capability.h>
 #include <linux/uio.h>
+#include <linux/cdev.h>
 
 #include <asm/uaccess.h>
 
@@ -260,11 +261,26 @@
 	.owner	=	THIS_MODULE,
 };
 
+static struct cdev raw_cdev = {
+	.kobj	=	{.name = "raw", },
+	.owner	=	THIS_MODULE,
+};
+
 static int __init raw_init(void)
 {
 	int i;
+	dev_t dev = MKDEV(RAW_MAJOR, 0);
+
+	if (register_chrdev_region(dev, MAX_RAW_MINORS, "raw"))
+		goto error;
+
+	cdev_init(&raw_cdev, &raw_fops);
+	if (cdev_add(&raw_cdev, dev, MAX_RAW_MINORS)) {
+		kobject_put(&raw_cdev.kobj);
+		unregister_chrdev_region(dev, MAX_RAW_MINORS);
+		goto error;
+	}
 
-	register_chrdev(RAW_MAJOR, "raw", &raw_fops);
 	devfs_mk_cdev(MKDEV(RAW_MAJOR, 0),
 		      S_IFCHR | S_IRUGO | S_IWUGO,
 		      "raw/rawctl");
@@ -273,6 +289,10 @@
 			      S_IFCHR | S_IRUGO | S_IWUGO,
 			      "raw/raw%d", i);
 	return 0;
+
+error:
+	printk(KERN_ERR "error register raw device\n");
+	return 1;
 }
 
 static void __exit raw_exit(void)
@@ -283,7 +303,8 @@
 		devfs_remove("raw/raw%d", i);
 	devfs_remove("raw/rawctl");
 	devfs_remove("raw");
-	unregister_chrdev(RAW_MAJOR, "raw");
+	cdev_del(&raw_cdev);
+	unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS);
 }
 
 module_init(raw_init);
diff -Nru a/drivers/char/rtc.c b/drivers/char/rtc.c
--- a/drivers/char/rtc.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/char/rtc.c	Sat Apr  3 19:38:57 2004
@@ -110,6 +110,8 @@
 #define hpet_rtc_timer_init() 			do { } while (0)
 #define hpet_rtc_dropped_irq() 			0
 static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {return 0;}
+#else
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 #endif
 
 /*
diff -Nru a/drivers/char/sn_serial.c b/drivers/char/sn_serial.c
--- a/drivers/char/sn_serial.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/char/sn_serial.c	Sat Apr  3 19:38:56 2004
@@ -82,7 +82,6 @@
 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 @@
 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);
@@ -354,7 +352,7 @@
 		if (xmit_count > 0) {
 			result = sn_func->sal_puts((char *)start, xmit_count);
 			if (!result)
-				sn_debug_printf("\n*** synch_flush_xmit failed to flush\n");
+				DPRINTF("\n*** synch_flush_xmit failed to flush\n");
 			if (result > 0) {
 				xmit_count -= result;
 				sn_total_tx_count += result;
@@ -391,12 +389,12 @@
 	xmit_count = (head < tail) ?  (SN_SAL_BUFFER_SIZE - tail) : (head - tail);
 
 	if (xmit_count == 0)
-		sn_debug_printf("\n*** empty xmit_count\n");
+		DPRINTF("\n*** empty xmit_count\n");
 
 	/* use the ops, as we could be on the simulator */
 	result = sn_func->sal_puts((char *)start, xmit_count);
 	if (!result)
-		sn_debug_printf("\n*** error in synchronous sal_puts\n");
+		DPRINTF("\n*** error in synchronous sal_puts\n");
 	/* XXX chadt clean this up */
 	if (result > 0) {
 		xmit_count -= result;
@@ -449,7 +447,7 @@
 			result = ia64_sn_console_xmit_chars((char *)start, xmit_count);
 #ifdef DEBUG
 			if (!result)
-				sn_debug_printf("`");
+				DPRINTF("`");
 #endif
 			if (result > 0) {
 				xmit_count -= result;
@@ -513,7 +511,7 @@
 	if (result >= 0)
 		return console_irq;
 
-	printk(KERN_INFO "sn_serial: console proceeding in polled mode\n");
+	printk(KERN_WARNING "sn_serial: console proceeding in polled mode\n");
 	return 0;
 }
 
@@ -825,7 +823,7 @@
 		return;
 	}
 
-	sn_debug_printf("sn_serial: switch to asynchronous console\n");
+	DPRINTF("sn_serial: switch to asynchronous console\n");
 
 	/* early_printk invocation may have done this for us */
 	if (!sn_func) {
@@ -861,7 +859,7 @@
 {
 	int irq;
 
-	sn_debug_printf("sn_serial: switching to interrupt driven console\n");
+	DPRINTF("sn_serial: switching to interrupt driven console\n");
 
 	irq = sn_sal_connect_interrupt();
 	if (irq) {
@@ -885,7 +883,7 @@
 {
 	int retval;
 
-	printk("sn_serial: sn_sal_module_init\n");
+	DPRINTF("sn_serial: sn_sal_module_init\n");
 
 	if (!ia64_platform_is("sn2"))
 		return -ENODEV;
@@ -921,9 +919,6 @@
 		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 @@
 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,16 +955,38 @@
 	 * 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
+	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);
+	}
 }
 
 static struct tty_driver *
@@ -993,14 +1011,16 @@
 	.index = -1
 };
 
-static void __init
+static int __init
 sn_sal_serial_console_init(void)
 {
 	if (ia64_platform_is("sn2")) {
 		sn_sal_switch_to_asynch();
-		sn_debug_printf("sn_sal_serial_console_init : register console\n");
+		DPRINTF("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 -Nru a/drivers/char/sonypi.c b/drivers/char/sonypi.c
--- a/drivers/char/sonypi.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/char/sonypi.c	Sat Apr  3 19:38:54 2004
@@ -129,7 +129,7 @@
 }
 
 /* Initializes the device - this comes from the AML code in the ACPI bios */
-static void __devinit sonypi_type1_srs(void) {
+static void sonypi_type1_srs(void) {
 	u32 v;
 
 	pci_read_config_dword(sonypi_device.dev, SONYPI_G10A, &v);
@@ -151,7 +151,7 @@
 	pci_write_config_dword(sonypi_device.dev, SONYPI_G10A, v);
 }
 
-static void __devinit sonypi_type2_srs(void) {
+static void sonypi_type2_srs(void) {
 	if (sonypi_ec_write(SONYPI_SHIB, (sonypi_device.ioport1 & 0xFF00) >> 8))
 		printk(KERN_WARNING "ec_write failed\n");
 	if (sonypi_ec_write(SONYPI_SLOB,  sonypi_device.ioport1 & 0x00FF))
diff -Nru a/drivers/char/sonypi.h b/drivers/char/sonypi.h
--- a/drivers/char/sonypi.h	Sat Apr  3 19:38:44 2004
+++ b/drivers/char/sonypi.h	Sat Apr  3 19:38:44 2004
@@ -37,7 +37,7 @@
 #ifdef __KERNEL__
 
 #define SONYPI_DRIVER_MAJORVERSION	 1
-#define SONYPI_DRIVER_MINORVERSION	21
+#define SONYPI_DRIVER_MINORVERSION	22
 
 #define SONYPI_DEVICE_MODEL_TYPE1	1
 #define SONYPI_DEVICE_MODEL_TYPE2	2
@@ -396,7 +396,6 @@
 }
 
 #ifdef CONFIG_ACPI
-extern int acpi_disabled;
 #define SONYPI_ACPI_ACTIVE (!acpi_disabled)
 #else
 #define SONYPI_ACPI_ACTIVE 0
diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c
--- a/drivers/char/synclink.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/synclink.c	Sat Apr  3 19:38:42 2004
@@ -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(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 @@
 	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 @@
 
 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 -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
--- a/drivers/char/synclinkmp.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/synclinkmp.c	Sat Apr  3 19:38:41 2004
@@ -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(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 @@
 	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 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 @@
 	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 -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/char/tty_io.c	Sat Apr  3 19:38:44 2004
@@ -2195,8 +2195,6 @@
 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 +2254,6 @@
 	int error;
         int i;
 	dev_t dev;
-	char *s;
 	void **p = NULL;
 
 	if (driver->flags & TTY_DRIVER_INSTALLED)
@@ -2296,15 +2293,11 @@
 		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 +2413,9 @@
 }
 
 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 +2430,6 @@
  */
 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 +2437,6 @@
 	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 +2444,7 @@
 	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 +2454,6 @@
 #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 -Nru a/drivers/char/viocons.c b/drivers/char/viocons.c
--- a/drivers/char/viocons.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/char/viocons.c	Sat Apr  3 19:38:40 2004
@@ -9,7 +9,7 @@
  *           Colin Devilbiss <devilbis@us.ibm.com>
  *           Stephen Rothwell <sfr@au1.ibm.com>
  *
- * (C) Copyright 2000, 2001, 2002, 2003 IBM Corporation
+ * (C) Copyright 2000, 2001, 2002, 2003, 2004 IBM Corporation
  *
  * This program is free software;  you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -57,7 +57,9 @@
 
 #define VIOTTY_MAGIC (0x0DCB)
 #define VTTY_PORTS 10
-#define VIOTTY_SERIAL_START 65
+
+#define VIOCONS_KERN_WARN	KERN_WARNING "viocons: "
+#define VIOCONS_KERN_INFO	KERN_INFO "viocons: "
 
 static spinlock_t consolelock = SPIN_LOCK_UNLOCKED;
 static spinlock_t consoleloglock = SPIN_LOCK_UNLOCKED;
@@ -138,7 +140,6 @@
 static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp);
 
 static struct tty_driver *viotty_driver;
-static struct tty_driver *viottyS_driver;
 
 void hvlog(char *fmt, ...)
 {
@@ -189,10 +190,10 @@
 static inline int viotty_paranoia_check(struct port_info *pi,
 					char *name, const char *routine)
 {
-	static const char *bad_pi_addr = KERN_WARNING_VIO
-		"Warning: bad address for port_info struct (%s) in %s\n";
-	static const char *badmagic = KERN_WARNING_VIO
-		"Warning: bad magic number for port_info struct (%s) in %s\n";
+	static const char *bad_pi_addr = VIOCONS_KERN_WARN
+		"warning: bad address for port_info struct (%s) in %s\n";
+	static const char *badmagic = VIOCONS_KERN_WARN
+		"warning: bad magic number for port_info struct (%s) in %s\n";
 
 	if ((pi < &port_info[0]) || (viochar_port(pi) > VTTY_PORTS)) {
 		printk(bad_pi_addr, name, routine);
@@ -395,8 +396,8 @@
 			vio_free_event_buffer(viomajorsubtype_chario, viochar);
 			spin_unlock_irqrestore(&consolelock, flags);
 
-			printk(KERN_WARNING_VIO
-			       "console error sending event! return code %d\n",
+			printk(VIOCONS_KERN_WARN
+			       "error sending event! return code %d\n",
 			       (int)hvrc);
 			return;
 		}
@@ -655,14 +656,14 @@
  * console device I/O methods
  */
 static struct console viocons_early = {
-	.name = "ttyS",
+	.name = "viocons",
 	.write = viocons_write_early,
 	.flags = CON_PRINTBUFFER,
 	.index = -1,
 };
 
 static struct console viocons = {
-	.name = "ttyS",
+	.name = "viocons",
 	.write = viocons_write,
 	.device = viocons_device,
 	.flags = CON_PRINTBUFFER,
@@ -680,9 +681,6 @@
 
 	port = tty->index;
 
-	if (port >= VIOTTY_SERIAL_START)
-		port -= VIOTTY_SERIAL_START;
-
 	if ((port < 0) || (port >= VTTY_PORTS))
 		return -ENODEV;
 
@@ -692,8 +690,8 @@
 	/* If some other TTY is already connected here, reject the open */
 	if ((pi->tty) && (pi->tty != tty)) {
 		spin_unlock_irqrestore(&consolelock, flags);
-		printk(KERN_WARNING_VIO
-		       "console attempt to open device twice from different ttys\n");
+		printk(VIOCONS_KERN_WARN
+		       "attempt to open device twice from different ttys\n");
 		return -EBUSY;
 	}
 	tty->driver_data = pi;
@@ -820,13 +818,6 @@
 }
 
 /*
- * TTY flush_chars method
- */
-static void viotty_flush_chars(struct tty_struct *tty)
-{
-}
-
-/*
  * TTY write_room method
  */
 static int viotty_write_room(struct tty_struct *tty)
@@ -864,17 +855,13 @@
 }
 
 /*
- * TTY chars_in_buffer_room method
+ * TTY chars_in_buffer method
  */
 static int viotty_chars_in_buffer(struct tty_struct *tty)
 {
 	return 0;
 }
 
-static void viotty_flush_buffer(struct tty_struct *tty)
-{
-}
-
 static int viotty_ioctl(struct tty_struct *tty, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
@@ -894,43 +881,6 @@
 	return n_tty_ioctl(tty, file, cmd, arg);
 }
 
-static void viotty_throttle(struct tty_struct *tty)
-{
-}
-
-static void viotty_unthrottle(struct tty_struct *tty)
-{
-}
-
-static void viotty_set_termios(struct tty_struct *tty,
-		struct termios *old_termios)
-{
-}
-
-static void viotty_stop(struct tty_struct *tty)
-{
-}
-
-static void viotty_start(struct tty_struct *tty)
-{
-}
-
-static void viotty_hangup(struct tty_struct *tty)
-{
-}
-
-static void viotty_break(struct tty_struct *tty, int break_state)
-{
-}
-
-static void viotty_send_xchar(struct tty_struct *tty, char ch)
-{
-}
-
-static void viotty_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-}
-
 /*
  * Handle an open charLpEvent.  Could be either interrupt or ack
  */
@@ -964,23 +914,22 @@
 
 		spin_unlock_irqrestore(&consolelock, flags);
 		if (event->xRc != HvLpEvent_Rc_Good)
-			printk(KERN_WARNING_VIO
-			       "viocons: event->xRc != HvLpEvent_Rc_Good, event->xRc == (%d).\n",
+			printk(VIOCONS_KERN_WARN
+			       "handle_open_event: event->xRc == (%d).\n",
 			       event->xRc);
 
 		if (event->xCorrelationToken != 0) {
 			atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
 			atomic_set(aptr, 1);
 		} else
-			printk(KERN_WARNING_VIO
-			       "viocons: wierd...got open ack without atomic\n");
+			printk(VIOCONS_KERN_WARN
+			       "wierd...got open ack without atomic\n");
 		return;
 	}
 
 	/* This had better require an ack, otherwise complain */
 	if (event->xFlags.xAckInd != HvLpEvent_AckInd_DoAck) {
-		printk(KERN_WARNING_VIO
-		       "console: viocharopen without ack bit!\n");
+		printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n");
 		return;
 	}
 
@@ -1019,11 +968,10 @@
 	spin_unlock_irqrestore(&consolelock, flags);
 
 	if (reject == 1)
-		printk(KERN_WARNING_VIO
-			"viocons: console open rejected : bad virtual tty.\n");
+		printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n");
 	else if (reject == 2)
-		printk(KERN_WARNING_VIO
-			"viocons: console open rejected : console in exclusive use by another partition.\n");
+		printk(VIOCONS_KERN_WARN
+			"open rejected: console in exclusive use by another partition.\n");
 
 	/* Return the acknowledgement */
 	HvCallEvent_ackLpEvent(event);
@@ -1050,7 +998,8 @@
 
 	if (event->xFlags.xFunction == HvLpEvent_Function_Int) {
 		if (port >= VTTY_PORTS) {
-			printk(KERN_WARNING_VIO "viocons: close message from invalid virtual device.\n");
+			printk(VIOCONS_KERN_WARN
+					"close message from invalid virtual device.\n");
 			return;
 		}
 
@@ -1062,11 +1011,10 @@
 			port_info[port].lp = HvLpIndexInvalid;
 
 		spin_unlock_irqrestore(&consolelock, flags);
-		printk(KERN_INFO_VIO
-		       "console close from %d\n", event->xSourceLp);
+		printk(VIOCONS_KERN_INFO "close from %d\n", event->xSourceLp);
 	} else
-		printk(KERN_WARNING_VIO
-		       "console got unexpected close acknowlegement\n");
+		printk(VIOCONS_KERN_WARN
+				"got unexpected close acknowlegement\n");
 }
 
 /*
@@ -1079,12 +1027,11 @@
 	HvCall_writeLogBuffer(cevent->data, cevent->len);
 
 	if (cevent->data[0] == 0x01)
-		printk(KERN_INFO_VIO
-		       "console window resized to %d: %d: %d: %d\n",
+		printk(VIOCONS_KERN_INFO "window resized to %d: %d: %d: %d\n",
 		       cevent->data[1], cevent->data[2],
 		       cevent->data[3], cevent->data[4]);
 	else
-		printk(KERN_WARNING_VIO "console unknown config event\n");
+		printk(VIOCONS_KERN_WARN "unknown config event\n");
 }
 
 /*
@@ -1100,8 +1047,8 @@
 	u8 port = cevent->virtual_device;
 
 	if (port >= VTTY_PORTS) {
-		printk(KERN_WARNING_VIO
-		       "console data on invalid virtual device %d\n", port);
+		printk(VIOCONS_KERN_WARN "data on invalid virtual device %d\n",
+				port);
 		return;
 	}
 
@@ -1130,13 +1077,14 @@
 	tty = pi->tty;
 	if (tty == NULL) {
 		spin_unlock_irqrestore(&consolelock, flags);
-		printk(KERN_WARNING_VIO "no tty for virtual device %d\n", port);
+		printk(VIOCONS_KERN_WARN "no tty for virtual device %d\n",
+				port);
 		return;
 	}
 
 	if (tty->magic != TTY_MAGIC) {
 		spin_unlock_irqrestore(&consolelock, flags);
-		printk(KERN_WARNING_VIO "tty bad magic\n");
+		printk(VIOCONS_KERN_WARN "tty bad magic\n");
 		return;
 	}
 
@@ -1186,8 +1134,7 @@
 		 * have room for because it would fail without indication.
 		 */
 		if ((tty->flip.count + 1) > TTY_FLIPBUF_SIZE) {
-			printk(KERN_WARNING_VIO
-					"console input buffer overflow!\n");
+			printk(VIOCONS_KERN_WARN "input buffer overflow!\n");
 			break;
 		}
 		tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL);
@@ -1209,8 +1156,7 @@
 	u8 port = cevent->virtual_device;
 
 	if (port >= VTTY_PORTS) {
-		printk(KERN_WARNING_VIO
-		       "viocons: data on invalid virtual device\n");
+		printk(VIOCONS_KERN_WARN "data on invalid virtual device\n");
 		return;
 	}
 
@@ -1278,20 +1224,9 @@
 	.close = viotty_close,
 	.write = viotty_write,
 	.put_char = viotty_put_char,
-	.flush_chars = viotty_flush_chars,
 	.write_room = viotty_write_room,
 	.chars_in_buffer = viotty_chars_in_buffer,
-	.flush_buffer = viotty_flush_buffer,
 	.ioctl = viotty_ioctl,
-	.throttle = viotty_throttle,
-	.unthrottle = viotty_unthrottle,
-	.set_termios = viotty_set_termios,
-	.stop = viotty_stop,
-	.start = viotty_start,
-	.hangup = viotty_hangup,
-	.break_ctl = viotty_break,
-	.send_xchar = viotty_send_xchar,
-	.wait_until_sent = viotty_wait_until_sent,
 };
 
 static int __init viocons_init2(void)
@@ -1299,14 +1234,11 @@
 	atomic_t wait_flag;
 	int rc;
 
-	/* Now open to the primary LP */
-	printk(KERN_INFO_VIO "console open path to primary\n");
 	/* +2 for fudge */
 	rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
 			viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
 	if (rc)
-		printk(KERN_WARNING_VIO "console error opening to primary %d\n",
-				rc);
+		printk(VIOCONS_KERN_WARN "error opening to primary %d\n", rc);
 
 	if (viopath_hostLp == HvLpIndexInvalid)
 		vio_set_hostlp();
@@ -1317,30 +1249,28 @@
 	 */
 	if ((viopath_hostLp != HvLpIndexInvalid) &&
 	    (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
-		printk(KERN_INFO_VIO "console open path to hosting (%d)\n",
+		printk(VIOCONS_KERN_INFO "open path to hosting (%d)\n",
 				viopath_hostLp);
 		rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
 				VIOCHAR_WINDOW + 2);	/* +2 for fudge */
 		if (rc)
-			printk(KERN_WARNING_VIO
-				"console error opening to partition %d: %d\n",
+			printk(VIOCONS_KERN_WARN
+				"error opening to partition %d: %d\n",
 				viopath_hostLp, rc);
 	}
 
 	if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0)
-		printk(KERN_WARNING_VIO
-				"Error seting handler for console events!\n");
+		printk(VIOCONS_KERN_WARN
+				"error seting handler for console events!\n");
 
-	printk(KERN_INFO_VIO "console major number is %d\n", TTY_MAJOR);
-
-	/* First, try to open the console to the hosting lp.
+	/*
+	 * First, try to open the console to the hosting lp.
 	 * Wait on a semaphore for the response.
 	 */
 	atomic_set(&wait_flag, 0);
 	if ((viopath_isactive(viopath_hostLp)) &&
 	    (send_open(viopath_hostLp, (void *)&wait_flag) == 0)) {
-		printk(KERN_INFO_VIO
-			"opening console to hosting partition %d\n",
+		printk(VIOCONS_KERN_INFO "hosting partition %d\n",
 			viopath_hostLp);
 		while (atomic_read(&wait_flag) == 0)
 			mb();
@@ -1354,7 +1284,7 @@
 	    (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
 	    (send_open(HvLpConfig_getPrimaryLpIndex(), (void *)&wait_flag)
 	     == 0)) {
-		printk(KERN_INFO_VIO "opening console to primary partition\n");
+		printk(VIOCONS_KERN_INFO "opening console to primary partition\n");
 		while (atomic_read(&wait_flag) == 0)
 			mb();
 	}
@@ -1365,6 +1295,7 @@
 	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;
@@ -1373,31 +1304,12 @@
 	viotty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
 	tty_set_operations(viotty_driver, &serial_ops);
 
-	viottyS_driver = alloc_tty_driver(VTTY_PORTS);
-	viottyS_driver->owner = THIS_MODULE;
-	viottyS_driver->driver_name = "vioconsole";
-	viottyS_driver->devfs_name = "tts/";
-	viottyS_driver->name = "ttyS";
-	viottyS_driver->major = TTY_MAJOR;
-	viottyS_driver->minor_start = VIOTTY_SERIAL_START;
-	viottyS_driver->type = TTY_DRIVER_TYPE_SERIAL;
-	viottyS_driver->subtype = 1;
-	viottyS_driver->init_termios = tty_std_termios;
-	viottyS_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-	tty_set_operations(viottyS_driver, &serial_ops);
-
 	if (tty_register_driver(viotty_driver)) {
-		printk(KERN_WARNING_VIO "Couldn't register console driver\n");
+		printk(VIOCONS_KERN_WARN "couldn't register console driver\n");
 		put_tty_driver(viotty_driver);
 		viotty_driver = NULL;
 	}
 
-	if (tty_register_driver(viottyS_driver)) {
-		printk(KERN_WARNING_VIO "Couldn't register console S driver\n");
-		put_tty_driver(viottyS_driver);
-		viottyS_driver = NULL;
-	}
-
 	viocons_init_cfu_buffer();
 
 	unregister_console(&viocons_early);
@@ -1410,7 +1322,7 @@
 {
 	int i;
 
-	printk(KERN_INFO_VIO "registering console\n");
+	printk(VIOCONS_KERN_INFO "registering console\n");
 	for (i = 0; i < VTTY_PORTS; i++) {
 		port_info[i].lp = HvLpIndexInvalid;
 		port_info[i].magic = VIOTTY_MAGIC;
diff -Nru a/drivers/char/viotape.c b/drivers/char/viotape.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/viotape.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,1055 @@
+/* -*- linux-c -*-
+ *  drivers/char/viotape.c
+ *
+ *  iSeries Virtual Tape
+ *
+ *  Authors: Dave Boutcher <boutcher@us.ibm.com>
+ *           Ryan Arnold <ryanarn@us.ibm.com>
+ *           Colin Devilbiss <devilbis@us.ibm.com>
+ *           Stephen Rothwell <sfr@au1.ibm.com>
+ *
+ * (C) Copyright 2000-2004 IBM Corporation
+ *
+ * This program is free software;  you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) anyu later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This routine provides access to tape drives owned and managed by an OS/400
+ * partition running on the same box as this Linux partition.
+ *
+ * All tape operations are performed by sending messages back and forth to
+ * the OS/400 partition.  The format of the messages is defined in
+ * iSeries/vio.h
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/mtio.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/major.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/ioctls.h>
+
+#include <asm/iSeries/vio.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvCallEvent.h>
+#include <asm/iSeries/HvLpConfig.h>
+
+#define VIOTAPE_VERSION		"1.1"
+#define VIOTAPE_MAXREQ		1
+
+#define VIOTAPE_KERN_WARN	KERN_WARNING "viotape: "
+#define VIOTAPE_KERN_INFO	KERN_INFO "viotape: "
+
+static int viotape_numdev;
+
+/*
+ * The minor number follows the conventions of the SCSI tape drives.  The
+ * rewind and mode are encoded in the minor #.  We use this struct to break
+ * them out
+ */
+struct viot_devinfo_struct {
+	int devno;
+	int mode;
+	int rewind;
+};
+
+#define VIOTAPOP_RESET          0
+#define VIOTAPOP_FSF	        1
+#define VIOTAPOP_BSF	        2
+#define VIOTAPOP_FSR	        3
+#define VIOTAPOP_BSR	        4
+#define VIOTAPOP_WEOF	        5
+#define VIOTAPOP_REW	        6
+#define VIOTAPOP_NOP	        7
+#define VIOTAPOP_EOM	        8
+#define VIOTAPOP_ERASE          9
+#define VIOTAPOP_SETBLK        10
+#define VIOTAPOP_SETDENSITY    11
+#define VIOTAPOP_SETPOS	       12
+#define VIOTAPOP_GETPOS	       13
+#define VIOTAPOP_SETPART       14
+#define VIOTAPOP_UNLOAD        15
+
+struct viotapelpevent {
+	struct HvLpEvent event;
+	u32 reserved;
+	u16 version;
+	u16 sub_type_result;
+	u16 tape;
+	u16 flags;
+	u32 token;
+	u64 len;
+	union {
+		struct {
+			u32 tape_op;
+			u32 count;
+		} op;
+		struct {
+			u32 type;
+			u32 resid;
+			u32 dsreg;
+			u32 gstat;
+			u32 erreg;
+			u32 file_no;
+			u32 block_no;
+		} get_status;
+		struct {
+			u32 block_no;
+		} get_pos;
+	} u;
+};
+
+enum viotapesubtype {
+	viotapeopen = 0x0001,
+	viotapeclose = 0x0002,
+	viotaperead = 0x0003,
+	viotapewrite = 0x0004,
+	viotapegetinfo = 0x0005,
+	viotapeop = 0x0006,
+	viotapegetpos = 0x0007,
+	viotapesetpos = 0x0008,
+	viotapegetstatus = 0x0009
+};
+
+enum viotaperc {
+	viotape_InvalidRange = 0x0601,
+	viotape_InvalidToken = 0x0602,
+	viotape_DMAError = 0x0603,
+	viotape_UseError = 0x0604,
+	viotape_ReleaseError = 0x0605,
+	viotape_InvalidTape = 0x0606,
+	viotape_InvalidOp = 0x0607,
+	viotape_TapeErr = 0x0608,
+
+	viotape_AllocTimedOut = 0x0640,
+	viotape_BOTEnc = 0x0641,
+	viotape_BlankTape = 0x0642,
+	viotape_BufferEmpty = 0x0643,
+	viotape_CleanCartFound = 0x0644,
+	viotape_CmdNotAllowed = 0x0645,
+	viotape_CmdNotSupported = 0x0646,
+	viotape_DataCheck = 0x0647,
+	viotape_DecompressErr = 0x0648,
+	viotape_DeviceTimeout = 0x0649,
+	viotape_DeviceUnavail = 0x064a,
+	viotape_DeviceBusy = 0x064b,
+	viotape_EndOfMedia = 0x064c,
+	viotape_EndOfTape = 0x064d,
+	viotape_EquipCheck = 0x064e,
+	viotape_InsufficientRs = 0x064f,
+	viotape_InvalidLogBlk = 0x0650,
+	viotape_LengthError = 0x0651,
+	viotape_LibDoorOpen = 0x0652,
+	viotape_LoadFailure = 0x0653,
+	viotape_NotCapable = 0x0654,
+	viotape_NotOperational = 0x0655,
+	viotape_NotReady = 0x0656,
+	viotape_OpCancelled = 0x0657,
+	viotape_PhyLinkErr = 0x0658,
+	viotape_RdyNotBOT = 0x0659,
+	viotape_TapeMark = 0x065a,
+	viotape_WriteProt = 0x065b
+};
+
+static const struct vio_error_entry viotape_err_table[] = {
+	{ viotape_InvalidRange, EIO, "Internal error" },
+	{ viotape_InvalidToken, EIO, "Internal error" },
+	{ viotape_DMAError, EIO, "DMA error" },
+	{ viotape_UseError, EIO, "Internal error" },
+	{ viotape_ReleaseError, EIO, "Internal error" },
+	{ viotape_InvalidTape, EIO, "Invalid tape device" },
+	{ viotape_InvalidOp, EIO, "Invalid operation" },
+	{ viotape_TapeErr, EIO, "Tape error" },
+	{ viotape_AllocTimedOut, EBUSY, "Allocate timed out" },
+	{ viotape_BOTEnc, EIO, "Beginning of tape encountered" },
+	{ viotape_BlankTape, EIO, "Blank tape" },
+	{ viotape_BufferEmpty, EIO, "Buffer empty" },
+	{ viotape_CleanCartFound, ENOMEDIUM, "Cleaning cartridge found" },
+	{ viotape_CmdNotAllowed, EIO, "Command not allowed" },
+	{ viotape_CmdNotSupported, EIO, "Command not supported" },
+	{ viotape_DataCheck, EIO, "Data check" },
+	{ viotape_DecompressErr, EIO, "Decompression error" },
+	{ viotape_DeviceTimeout, EBUSY, "Device timeout" },
+	{ viotape_DeviceUnavail, EIO, "Device unavailable" },
+	{ viotape_DeviceBusy, EBUSY, "Device busy" },
+	{ viotape_EndOfMedia, ENOSPC, "End of media" },
+	{ viotape_EndOfTape, ENOSPC, "End of tape" },
+	{ viotape_EquipCheck, EIO, "Equipment check" },
+	{ viotape_InsufficientRs, EOVERFLOW, "Insufficient tape resources" },
+	{ viotape_InvalidLogBlk, EIO, "Invalid logical block location" },
+	{ viotape_LengthError, EOVERFLOW, "Length error" },
+	{ viotape_LibDoorOpen, EBUSY, "Door open" },
+	{ viotape_LoadFailure, ENOMEDIUM, "Load failure" },
+	{ viotape_NotCapable, EIO, "Not capable" },
+	{ viotape_NotOperational, EIO, "Not operational" },
+	{ viotape_NotReady, EIO, "Not ready" },
+	{ viotape_OpCancelled, EIO, "Operation cancelled" },
+	{ viotape_PhyLinkErr, EIO, "Physical link error" },
+	{ viotape_RdyNotBOT, EIO, "Ready but not beginning of tape" },
+	{ viotape_TapeMark, EIO, "Tape mark" },
+	{ viotape_WriteProt, EROFS, "Write protection error" },
+	{ 0, 0, NULL },
+};
+
+/* Maximum number of tapes we support */
+#define VIOTAPE_MAX_TAPE	8
+#define MAX_PARTITIONS		4
+
+/* defines for current tape state */
+#define VIOT_IDLE		0
+#define VIOT_READING		1
+#define VIOT_WRITING		2
+
+/* Our info on the tapes */
+struct tape_descr {
+	char rsrcname[10];
+	char type[4];
+	char model[3];
+};
+
+static struct tape_descr *viotape_unitinfo;
+static dma_addr_t viotape_unitinfo_token;
+
+static struct mtget viomtget[VIOTAPE_MAX_TAPE];
+
+static struct class_simple *tape_class;
+
+/*
+ * maintain the current state of each tape (and partition)
+ * so that we know when to write EOF marks.
+ */
+static struct {
+	unsigned char	cur_part;
+	int		dev_handle;
+	unsigned char	part_stat_rwi[MAX_PARTITIONS];
+} state[VIOTAPE_MAX_TAPE];
+
+/* We single-thread */
+static struct semaphore reqSem;
+
+/*
+ * When we send a request, we use this struct to get the response back
+ * from the interrupt handler
+ */
+struct op_struct {
+	void			*buffer;
+	dma_addr_t		dmaaddr;
+	size_t			count;
+	int			rc;
+	int			non_blocking;
+	struct completion	com;
+	struct op_struct	*next;
+};
+
+static spinlock_t	op_struct_list_lock;
+static struct op_struct	*op_struct_list;
+
+/* forward declaration to resolve interdependence */
+static int chg_state(int index, unsigned char new_state, struct file *file);
+
+/* Decode the device minor number into its parts */
+void get_dev_info(struct inode *ino, struct viot_devinfo_struct *devi)
+{
+	devi->devno = iminor(ino) & 0x1F;
+	devi->mode = (iminor(ino) & 0x60) >> 5;
+	/* if bit is set in the minor, do _not_ rewind automatically */
+	devi->rewind = (iminor(ino) & 0x80) == 0;
+}
+
+/* This is called only from the exit and init paths, so no need for locking */
+static void clear_op_struct_pool(void)
+{
+	while (op_struct_list) {
+		struct op_struct *toFree = op_struct_list;
+		op_struct_list = op_struct_list->next;
+		kfree(toFree);
+	}
+}
+
+/* Likewise, this is only called from the init path */
+static int add_op_structs(int structs)
+{
+	int i;
+
+	for (i = 0; i < structs; ++i) {
+		struct op_struct *new_struct =
+			kmalloc(sizeof(*new_struct), GFP_KERNEL);
+		if (!new_struct) {
+			clear_op_struct_pool();
+			return -ENOMEM;
+		}
+		new_struct->next = op_struct_list;
+		op_struct_list = new_struct;
+	}
+	return 0;
+}
+
+/* Allocate an op structure from our pool */
+static struct op_struct *get_op_struct(void)
+{
+	struct op_struct *retval;
+	unsigned long flags;
+
+	spin_lock_irqsave(&op_struct_list_lock, flags);
+	retval = op_struct_list;
+	if (retval)
+		op_struct_list = retval->next;
+	spin_unlock_irqrestore(&op_struct_list_lock, flags);
+	if (retval) {
+		memset(retval, 0, sizeof(*retval));
+		init_completion(&retval->com);
+	}
+
+	return retval;
+}
+
+/* Return an op structure to our pool */
+static void free_op_struct(struct op_struct *op_struct)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&op_struct_list_lock, flags);
+	op_struct->next = op_struct_list;
+	op_struct_list = op_struct;
+	spin_unlock_irqrestore(&op_struct_list_lock, flags);
+}
+
+/* Map our tape return codes to errno values */
+int tape_rc_to_errno(int tape_rc, char *operation, int tapeno)
+{
+	const struct vio_error_entry *err;
+
+	if (tape_rc == 0)
+		return 0;
+
+	err = vio_lookup_rc(viotape_err_table, tape_rc);
+	printk(VIOTAPE_KERN_WARN "error(%s) 0x%04x on Device %d (%-10s): %s\n",
+			operation, tape_rc, tapeno,
+			viotape_unitinfo[tapeno].rsrcname, err->msg);
+	return -err->errno;
+}
+
+/* Get info on all tapes from OS/400 */
+static int get_viotape_info(void)
+{
+	HvLpEvent_Rc hvrc;
+	int i;
+	size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE;
+	struct op_struct *op = get_op_struct();
+
+	if (op == NULL)
+		return -ENOMEM;
+
+	viotape_unitinfo = dma_alloc_coherent(iSeries_vio_dev, len,
+		&viotape_unitinfo_token, GFP_ATOMIC);
+	if (viotape_unitinfo == NULL) {
+		free_op_struct(op);
+		return -ENOMEM;
+	}
+
+	memset(viotape_unitinfo, 0, len);
+
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_tape | viotapegetinfo,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64) (unsigned long) op, VIOVERSION << 16,
+			viotape_unitinfo_token, len, 0, 0);
+	if (hvrc != HvLpEvent_Rc_Good) {
+		printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
+				(int)hvrc);
+		free_op_struct(op);
+		return -EIO;
+	}
+
+	wait_for_completion(&op->com);
+
+	free_op_struct(op);
+
+	for (i = 0;
+	     ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0]));
+	     i++)
+		viotape_numdev++;
+	return 0;
+}
+
+
+/* Write */
+static ssize_t viotap_write(struct file *file, const char *buf,
+		size_t count, loff_t * ppos)
+{
+	HvLpEvent_Rc hvrc;
+	unsigned short flags = file->f_flags;
+	int noblock = ((flags & O_NONBLOCK) != 0);
+	ssize_t ret;
+	struct viot_devinfo_struct devi;
+	struct op_struct *op = get_op_struct();
+
+	if (op == NULL)
+		return -ENOMEM;
+
+	get_dev_info(file->f_dentry->d_inode, &devi);
+
+	/*
+	 * We need to make sure we can send a request.  We use
+	 * a semaphore to keep track of # requests in use.  If
+	 * we are non-blocking, make sure we don't block on the
+	 * semaphore
+	 */
+	if (noblock) {
+		if (down_trylock(&reqSem)) {
+			ret = -EWOULDBLOCK;
+			goto free_op;
+		}
+	} else
+		down(&reqSem);
+
+	/* Allocate a DMA buffer */
+	op->buffer = dma_alloc_coherent(iSeries_vio_dev, count, &op->dmaaddr,
+			GFP_ATOMIC);
+
+	if (op->buffer == NULL) {
+		printk(VIOTAPE_KERN_WARN
+				"error allocating dma buffer for len %ld\n",
+				count);
+		ret = -EFAULT;
+		goto up_sem;
+	}
+
+	/* Copy the data into the buffer */
+	if (copy_from_user(op->buffer, buf, count)) {
+		printk(VIOTAPE_KERN_WARN "tape: error on copy from user\n");
+		ret = -EFAULT;
+		goto free_dma;
+	}
+
+	op->non_blocking = noblock;
+	init_completion(&op->com);
+	op->count = count;
+
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_tape | viotapewrite,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)(unsigned long)op, VIOVERSION << 16,
+			((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);
+	if (hvrc != HvLpEvent_Rc_Good) {
+		printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
+				(int)hvrc);
+		ret = -EIO;
+		goto free_dma;
+	}
+
+	if (noblock)
+		return count;
+
+	wait_for_completion(&op->com);
+
+	if (op->rc)
+		ret = tape_rc_to_errno(op->rc, "write", devi.devno);
+	else {
+		chg_state(devi.devno, VIOT_WRITING, file);
+		ret = op->count;
+	}
+
+free_dma:
+	dma_free_coherent(iSeries_vio_dev, count, op->buffer, op->dmaaddr);
+up_sem:
+	up(&reqSem);
+free_op:
+	free_op_struct(op);
+	return ret;
+}
+
+/* read */
+static ssize_t viotap_read(struct file *file, char *buf, size_t count,
+		loff_t *ptr)
+{
+	HvLpEvent_Rc hvrc;
+	unsigned short flags = file->f_flags;
+	struct op_struct *op = get_op_struct();
+	int noblock = ((flags & O_NONBLOCK) != 0);
+	ssize_t ret;
+	struct viot_devinfo_struct devi;
+
+	if (op == NULL)
+		return -ENOMEM;
+
+	get_dev_info(file->f_dentry->d_inode, &devi);
+
+	/*
+	 * We need to make sure we can send a request.  We use
+	 * a semaphore to keep track of # requests in use.  If
+	 * we are non-blocking, make sure we don't block on the
+	 * semaphore
+	 */
+	if (noblock) {
+		if (down_trylock(&reqSem)) {
+			ret = -EWOULDBLOCK;
+			goto free_op;
+		}
+	} else
+		down(&reqSem);
+
+	chg_state(devi.devno, VIOT_READING, file);
+
+	/* Allocate a DMA buffer */
+	op->buffer = dma_alloc_coherent(iSeries_vio_dev, count, &op->dmaaddr,
+			GFP_ATOMIC);
+	if (op->buffer == NULL) {
+		ret = -EFAULT;
+		goto up_sem;
+	}
+
+	op->count = count;
+	init_completion(&op->com);
+
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_tape | viotaperead,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)(unsigned long)op, VIOVERSION << 16,
+			((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0);
+	if (hvrc != HvLpEvent_Rc_Good) {
+		printk(VIOTAPE_KERN_WARN "tape hv error on op %d\n",
+				(int)hvrc);
+		ret = -EIO;
+		goto free_dma;
+	}
+
+	wait_for_completion(&op->com);
+
+	if (op->rc)
+		ret = tape_rc_to_errno(op->rc, "read", devi.devno);
+	else {
+		ret = op->count;
+		if (ret && copy_to_user(buf, op->buffer, ret)) {
+			printk(VIOTAPE_KERN_WARN "error on copy_to_user\n");
+			ret = -EFAULT;
+		}
+	}
+
+free_dma:
+	dma_free_coherent(iSeries_vio_dev, count, op->buffer, op->dmaaddr);
+up_sem:
+	up(&reqSem);
+free_op:
+	free_op_struct(op);
+	return ret;
+}
+
+/* ioctl */
+static int viotap_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	HvLpEvent_Rc hvrc;
+	int ret;
+	struct viot_devinfo_struct devi;
+	struct mtop mtc;
+	u32 myOp;
+	struct op_struct *op = get_op_struct();
+
+	if (op == NULL)
+		return -ENOMEM;
+
+	get_dev_info(file->f_dentry->d_inode, &devi);
+
+	down(&reqSem);
+
+	ret = -EINVAL;
+
+	switch (cmd) {
+	case MTIOCTOP:
+		ret = -EFAULT;
+		/*
+		 * inode is null if and only if we (the kernel)
+		 * made the request
+		 */
+		if (inode == NULL)
+			memcpy(&mtc, (void *) arg, sizeof(struct mtop));
+		else if (copy_from_user((char *)&mtc, (char *)arg,
+					sizeof(struct mtop)))
+			goto free_op;
+
+		ret = -EIO;
+		switch (mtc.mt_op) {
+		case MTRESET:
+			myOp = VIOTAPOP_RESET;
+			break;
+		case MTFSF:
+			myOp = VIOTAPOP_FSF;
+			break;
+		case MTBSF:
+			myOp = VIOTAPOP_BSF;
+			break;
+		case MTFSR:
+			myOp = VIOTAPOP_FSR;
+			break;
+		case MTBSR:
+			myOp = VIOTAPOP_BSR;
+			break;
+		case MTWEOF:
+			myOp = VIOTAPOP_WEOF;
+			break;
+		case MTREW:
+			myOp = VIOTAPOP_REW;
+			break;
+		case MTNOP:
+			myOp = VIOTAPOP_NOP;
+			break;
+		case MTEOM:
+			myOp = VIOTAPOP_EOM;
+			break;
+		case MTERASE:
+			myOp = VIOTAPOP_ERASE;
+			break;
+		case MTSETBLK:
+			myOp = VIOTAPOP_SETBLK;
+			break;
+		case MTSETDENSITY:
+			myOp = VIOTAPOP_SETDENSITY;
+			break;
+		case MTTELL:
+			myOp = VIOTAPOP_GETPOS;
+			break;
+		case MTSEEK:
+			myOp = VIOTAPOP_SETPOS;
+			break;
+		case MTSETPART:
+			myOp = VIOTAPOP_SETPART;
+			break;
+		case MTOFFL:
+			myOp = VIOTAPOP_UNLOAD;
+			break;
+		default:
+			printk(VIOTAPE_KERN_WARN "MTIOCTOP called "
+					"with invalid op 0x%x\n", mtc.mt_op);
+			goto free_op;
+		}
+
+		/*
+		 * if we moved the head, we are no longer
+		 * reading or writing
+		 */
+		switch (mtc.mt_op) {
+		case MTFSF:
+		case MTBSF:
+		case MTFSR:
+		case MTBSR:
+		case MTTELL:
+		case MTSEEK:
+		case MTREW:
+			chg_state(devi.devno, VIOT_IDLE, file);
+		}
+
+		init_completion(&op->com);
+		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+				HvLpEvent_Type_VirtualIo,
+				viomajorsubtype_tape | viotapeop,
+				HvLpEvent_AckInd_DoAck,
+				HvLpEvent_AckType_ImmediateAck,
+				viopath_sourceinst(viopath_hostLp),
+				viopath_targetinst(viopath_hostLp),
+				(u64)(unsigned long)op,
+				VIOVERSION << 16,
+				((u64)devi.devno << 48), 0,
+				(((u64)myOp) << 32) | mtc.mt_count, 0);
+		if (hvrc != HvLpEvent_Rc_Good) {
+			printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
+					(int)hvrc);
+			goto free_op;
+		}
+		wait_for_completion(&op->com);
+		ret = tape_rc_to_errno(op->rc, "tape operation", devi.devno);
+		goto free_op;
+
+	case MTIOCGET:
+		ret = -EIO;
+		init_completion(&op->com);
+		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+				HvLpEvent_Type_VirtualIo,
+				viomajorsubtype_tape | viotapegetstatus,
+				HvLpEvent_AckInd_DoAck,
+				HvLpEvent_AckType_ImmediateAck,
+				viopath_sourceinst(viopath_hostLp),
+				viopath_targetinst(viopath_hostLp),
+				(u64)(unsigned long)op, VIOVERSION << 16,
+				((u64)devi.devno << 48), 0, 0, 0);
+		if (hvrc != HvLpEvent_Rc_Good) {
+			printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
+					(int)hvrc);
+			goto free_op;
+		}
+		wait_for_completion(&op->com);
+
+		/* Operation is complete - grab the error code */
+		ret = tape_rc_to_errno(op->rc, "get status", devi.devno);
+		free_op_struct(op);
+		up(&reqSem);
+
+		if ((ret == 0) && copy_to_user((void *)arg,
+					&viomtget[devi.devno],
+					sizeof(viomtget[0])))
+			ret = -EFAULT;
+		return ret;
+	case MTIOCPOS:
+		printk(VIOTAPE_KERN_WARN "Got an (unsupported) MTIOCPOS\n");
+		break;
+	default:
+		printk(VIOTAPE_KERN_WARN "got an unsupported ioctl 0x%0x\n",
+				cmd);
+		break;
+	}
+
+free_op:
+	free_op_struct(op);
+	up(&reqSem);
+	return ret;
+}
+
+static int viotap_open(struct inode *inode, struct file *file)
+{
+	HvLpEvent_Rc hvrc;
+	struct viot_devinfo_struct devi;
+	int ret;
+	struct op_struct *op = get_op_struct();
+
+	if (op == NULL)
+		return -ENOMEM;
+
+	get_dev_info(file->f_dentry->d_inode, &devi);
+
+	/* Note: We currently only support one mode! */
+	if ((devi.devno >= viotape_numdev) || (devi.mode)) {
+		ret = -ENODEV;
+		goto free_op;
+	}
+
+	init_completion(&op->com);
+
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_tape | viotapeopen,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)(unsigned long)op, VIOVERSION << 16,
+			((u64)devi.devno << 48), 0, 0, 0);
+	if (hvrc != 0) {
+		printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",
+				(int) hvrc);
+		ret = -EIO;
+		goto free_op;
+	}
+
+	wait_for_completion(&op->com);
+	ret = tape_rc_to_errno(op->rc, "open", devi.devno);
+
+free_op:
+	free_op_struct(op);
+	return ret;
+}
+
+
+static int viotap_release(struct inode *inode, struct file *file)
+{
+	HvLpEvent_Rc hvrc;
+	struct viot_devinfo_struct devi;
+	int ret = 0;
+	struct op_struct *op = get_op_struct();
+
+	if (op == NULL)
+		return -ENOMEM;
+	init_completion(&op->com);
+
+	get_dev_info(file->f_dentry->d_inode, &devi);
+
+	if (devi.devno >= viotape_numdev) {
+		ret = -ENODEV;
+		goto free_op;
+	}
+
+	chg_state(devi.devno, VIOT_IDLE, file);
+
+	if (devi.rewind) {
+		hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+				HvLpEvent_Type_VirtualIo,
+				viomajorsubtype_tape | viotapeop,
+				HvLpEvent_AckInd_DoAck,
+				HvLpEvent_AckType_ImmediateAck,
+				viopath_sourceinst(viopath_hostLp),
+				viopath_targetinst(viopath_hostLp),
+				(u64)(unsigned long)op, VIOVERSION << 16,
+				((u64)devi.devno << 48), 0,
+				((u64)VIOTAPOP_REW) << 32, 0);
+		wait_for_completion(&op->com);
+
+		tape_rc_to_errno(op->rc, "rewind", devi.devno);
+	}
+
+	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
+			HvLpEvent_Type_VirtualIo,
+			viomajorsubtype_tape | viotapeclose,
+			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+			viopath_sourceinst(viopath_hostLp),
+			viopath_targetinst(viopath_hostLp),
+			(u64)(unsigned long)op, VIOVERSION << 16,
+			((u64)devi.devno << 48), 0, 0, 0);
+	if (hvrc != 0) {
+		printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n",
+				(int) hvrc);
+		ret = -EIO;
+		goto free_op;
+	}
+
+	wait_for_completion(&op->com);
+
+	if (op->rc)
+		printk(VIOTAPE_KERN_WARN "close failed\n");
+
+free_op:
+	free_op_struct(op);
+	return ret;
+}
+
+struct file_operations viotap_fops = {
+	owner: THIS_MODULE,
+	read: viotap_read,
+	write: viotap_write,
+	ioctl: viotap_ioctl,
+	open: viotap_open,
+	release: viotap_release,
+};
+
+/* Handle interrupt events for tape */
+static void vioHandleTapeEvent(struct HvLpEvent *event)
+{
+	int tapeminor;
+	struct op_struct *op;
+	struct viotapelpevent *tevent = (struct viotapelpevent *)event;
+
+	if (event == NULL) {
+		/* Notification that a partition went away! */
+		if (!viopath_isactive(viopath_hostLp)) {
+			/* TODO! Clean up */
+		}
+		return;
+	}
+
+	tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
+	op = (struct op_struct *)event->xCorrelationToken;
+	switch (tapeminor) {
+	case viotapegetinfo:
+	case viotapeopen:
+	case viotapeclose:
+		op->rc = tevent->sub_type_result;
+		complete(&op->com);
+		break;
+	case viotaperead:
+		op->rc = tevent->sub_type_result;
+		op->count = tevent->len;
+		complete(&op->com);
+		break;
+	case viotapewrite:
+		if (op->non_blocking) {
+			dma_free_coherent(iSeries_vio_dev, op->count,
+					op->buffer, op->dmaaddr);
+			free_op_struct(op);
+			up(&reqSem);
+		} else {
+			op->rc = tevent->sub_type_result;
+			op->count = tevent->len;
+			complete(&op->com);
+		}
+		break;
+	case viotapeop:
+	case viotapegetpos:
+	case viotapesetpos:
+	case viotapegetstatus:
+		if (op) {
+			op->count = tevent->u.op.count;
+			op->rc = tevent->sub_type_result;
+			if (!op->non_blocking)
+				complete(&op->com);
+		}
+		break;
+	default:
+		printk(VIOTAPE_KERN_WARN "wierd ack\n");
+	}
+}
+
+
+int __init viotap_init(void)
+{
+	int ret;
+	char tapename[32];
+	int i;
+
+	op_struct_list = NULL;
+	if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) {
+		printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n");
+		return ret;
+	}
+	spin_lock_init(&op_struct_list_lock);
+
+	sema_init(&reqSem, VIOTAPE_MAXREQ);
+
+	if (viopath_hostLp == HvLpIndexInvalid) {
+		vio_set_hostlp();
+		if (viopath_hostLp == HvLpIndexInvalid) {
+			ret = -ENODEV;
+			goto clear_op;
+		}
+	}
+
+	ret = viopath_open(viopath_hostLp, viomajorsubtype_tape,
+			VIOTAPE_MAXREQ + 2);
+	if (ret) {
+		printk(VIOTAPE_KERN_WARN
+				"error on viopath_open to hostlp %d\n", ret);
+		ret = -EIO;
+		goto clear_op;
+	}
+
+	printk(VIOTAPE_KERN_INFO "vers " VIOTAPE_VERSION
+			", hosting partition %d\n", viopath_hostLp);
+
+	vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent);
+
+	ret = register_chrdev(VIOTAPE_MAJOR, "viotape", &viotap_fops);
+	if (ret < 0) {
+		printk(VIOTAPE_KERN_WARN "Error registering viotape device\n");
+		goto clear_handler;
+	}
+
+	tape_class = class_simple_create(THIS_MODULE, "tape");
+	if (IS_ERR(tape_class)) {
+		printk(VIOTAPE_KERN_WARN "Unable to allocat class\n");
+		ret = PTR_ERR(tape_class);
+		goto unreg_chrdev;
+	}
+
+	if ((ret = get_viotape_info()) < 0) {
+		printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information");
+		goto unreg_class;
+	}
+
+	for (i = 0; i < viotape_numdev; i++) {
+		int j;
+
+		state[i].cur_part = 0;
+		for (j = 0; j < MAX_PARTITIONS; ++j)
+			state[i].part_stat_rwi[j] = VIOT_IDLE;
+		class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i),
+				NULL, "iseries!vt%d", i);
+		class_simple_device_add(tape_class,
+				MKDEV(VIOTAPE_MAJOR, i | 0x80),
+				NULL, "iseries!nvt%d", i);
+		devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i),
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				"iseries/vt%d", i);
+		devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80),
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				"iseries/nvt%d", i);
+		sprintf(tapename, "iseries/vt%d", i);
+		state[i].dev_handle = devfs_register_tape(tapename);
+		printk(VIOTAPE_KERN_INFO "tape %s is iSeries "
+				"resource %10.10s type %4.4s, model %3.3s\n",
+				tapename, viotape_unitinfo[i].rsrcname,
+				viotape_unitinfo[i].type,
+				viotape_unitinfo[i].model);
+	}
+
+	return 0;
+
+unreg_class:
+	class_simple_destroy(tape_class);
+unreg_chrdev:
+	unregister_chrdev(VIOTAPE_MAJOR, "viotape");
+clear_handler:
+	vio_clearHandler(viomajorsubtype_tape);
+	viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
+clear_op:
+	clear_op_struct_pool();
+	return ret;
+}
+
+/* Give a new state to the tape object */
+static int chg_state(int index, unsigned char new_state, struct file *file)
+{
+	unsigned char *cur_state =
+	    &state[index].part_stat_rwi[state[index].cur_part];
+	int rc = 0;
+
+	/* if the same state, don't bother */
+	if (*cur_state == new_state)
+		return 0;
+
+	/* write an EOF if changing from writing to some other state */
+	if (*cur_state == VIOT_WRITING) {
+		struct mtop write_eof = { MTWEOF, 1 };
+
+		rc = viotap_ioctl(NULL, file, MTIOCTOP,
+				  (unsigned long)&write_eof);
+	}
+	*cur_state = new_state;
+	return rc;
+}
+
+/* Cleanup */
+static void __exit viotap_exit(void)
+{
+	int i, ret;
+
+	for (i = 0; i < viotape_numdev; ++i) {
+		devfs_remove("iseries/nvt%d", i);
+		devfs_remove("iseries/vt%d", i);
+		devfs_unregister_tape(state[i].dev_handle);
+		class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80));
+		class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i));
+	}
+	class_simple_destroy(tape_class);
+	ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape");
+	if (ret < 0)
+		printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n",
+				ret);
+	if (viotape_unitinfo)
+		dma_free_coherent(iSeries_vio_dev,
+				sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,
+				viotape_unitinfo, viotape_unitinfo_token);
+	viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
+	vio_clearHandler(viomajorsubtype_tape);
+	clear_op_struct_pool();
+}
+
+MODULE_LICENSE("GPL");
+module_init(viotap_init);
+module_exit(viotap_exit);
diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c
--- a/drivers/char/vt.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/vt.c	Sat Apr  3 19:38:55 2004
@@ -2315,7 +2315,7 @@
 			break;
 		case TIOCL_SETVESABLANK:
 			set_vesa_blanking(arg);
-			break;;
+			break;
 		case TIOCL_SETKMSGREDIRECT:
 			if (!capable(CAP_SYS_ADMIN)) {
 				ret = -EPERM;
@@ -2481,19 +2481,20 @@
 	return 0;
 }
 
-static void con_close(struct tty_struct *tty, struct file * filp)
+static void con_close(struct tty_struct *tty, struct file *filp)
 {
-	struct vt_struct *vt;
-	
-	if (!tty || tty->count != 1)
-		return;
-
-	vcs_remove_devfs(tty);
 	acquire_console_sem();
-	vt = (struct vt_struct*)tty->driver_data;
-	if (vt)
-		vc_cons[vt->vc_num].d->vc_tty = NULL;
-	tty->driver_data = 0;
+	if (tty && tty->count == 1) {
+		struct vt_struct *vt;
+
+		vt = tty->driver_data;
+		if (vt)
+			vc_cons[vt->vc_num].d->vc_tty = NULL;
+		tty->driver_data = 0;
+		release_console_sem();
+		vcs_remove_devfs(tty);
+		return;
+	}
 	release_console_sem();
 }
 
diff -Nru a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
--- a/drivers/char/watchdog/Kconfig	Sat Apr  3 19:38:45 2004
+++ b/drivers/char/watchdog/Kconfig	Sat Apr  3 19:38:45 2004
@@ -374,7 +374,7 @@
 	tristate "Berkshire Products ISA-PC Watchdog"
 	depends on WATCHDOG && ISA
 	---help---
-	  This is the driver for the Berkshire Products PC Watchdog card.
+	  This is the driver for the Berkshire Products ISA-PC Watchdog card.
 	  This card simply watches your kernel to make sure it doesn't freeze,
 	  and if it does, it reboots your computer after a certain amount of
 	  time. This driver is like the WDT501 driver but for different
@@ -406,10 +406,8 @@
 	---help---
 	  If you have a WDT500P or WDT501P watchdog board, say Y here,
 	  otherwise N. It is not possible to probe for this board, which means
-	  that you have to inform the kernel about the IO port and IRQ using
-	  the "wdt=" kernel option (try "man bootparam" or see the
-	  documentation of your boot loader (lilo or loadlin) about how to
-	  pass options to the kernel at boot time).
+	  that you have to inform the kernel about the IO port and IRQ that
+	  is needed (you can do this via the io and irq parameters)
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called wdt.
@@ -425,11 +423,8 @@
 	  Fahrenheit. This works only if you have a WDT501P watchdog board
 	  installed.
 
-config WDT_501_FAN
-	bool "Fan Tachometer"
-	depends on WDT_501
-	help
-	  Enable the Fan Tachometer on the WDT501. Only do this if you have a
+	  If you want to enable the Fan Tachometer on the WDT501P, then you
+	  can do this via the tachometer parameter. Only do this if you have a
 	  fan tachometer actually set up.
 
 #
@@ -455,29 +450,28 @@
 	  Most people will say N.
 
 config WDTPCI
-	tristate "WDT PCI Watchdog timer"
+	tristate "PCI-WDT500/501 Watchdog timer"
 	depends on WATCHDOG && PCI
 	---help---
-	  If you have a PCI WDT500/501 watchdog board, say Y here, otherwise
-	  N.  It is not possible to probe for this board, which means that you
-	  have to inform the kernel about the IO port and IRQ using the "wdt="
-	  kernel option (try "man bootparam" or see the documentation of your
-	  boot loader (lilo or loadlin) about how to pass options to the
-	  kernel at boot time).
+	  If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called wdt_pci.
 
 config WDT_501_PCI
-	bool "WDT501-PCI features"
+	bool "PCI-WDT501 features"
 	depends on WDTPCI
 	help
 	  Saying Y here and creating a character special file /dev/temperature
 	  with major number 10 and minor number 131 ("man mknod") will give
 	  you a thermometer inside your computer: reading from
 	  /dev/temperature yields one byte, the temperature in degrees
-	  Fahrenheit. This works only if you have a WDT501P watchdog board
+	  Fahrenheit. This works only if you have a PCI-WDT501 watchdog board
 	  installed.
+
+	  If you want to enable the Fan Tachometer on the PCI-WDT501, then you
+	  can do this via the tachometer parameter. Only do this if you have a
+	  fan tachometer actually set up.
 
 #
 # USB-based Watchdog Cards
diff -Nru a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
--- a/drivers/char/watchdog/advantechwdt.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/char/watchdog/advantechwdt.c	Sat Apr  3 19:38:43 2004
@@ -256,8 +256,6 @@
 
 static struct notifier_block advwdt_notifier = {
 	.notifier_call = advwdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init
diff -Nru a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
--- a/drivers/char/watchdog/alim1535_wdt.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/watchdog/alim1535_wdt.c	Sat Apr  3 19:38:42 2004
@@ -385,8 +385,6 @@
 
 static struct notifier_block ali_notifier = {
 	.notifier_call =	ali_notify_sys,
-	.next =			NULL,
-	.priority =		0,
 };
 
 /*
diff -Nru a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
--- a/drivers/char/watchdog/alim7101_wdt.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/char/watchdog/alim7101_wdt.c	Sat Apr  3 19:38:54 2004
@@ -303,8 +303,6 @@
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = 0,
-	.priority = 0,
 };
 
 static void __exit alim7101_wdt_unload(void)
diff -Nru a/drivers/char/watchdog/amd7xx_tco.c b/drivers/char/watchdog/amd7xx_tco.c
--- a/drivers/char/watchdog/amd7xx_tco.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/watchdog/amd7xx_tco.c	Sat Apr  3 19:38:42 2004
@@ -365,25 +365,6 @@
 	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 -Nru a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
--- a/drivers/char/watchdog/cpu5wdt.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/watchdog/cpu5wdt.c	Sat Apr  3 19:38:42 2004
@@ -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_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 -Nru a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
--- a/drivers/char/watchdog/eurotechwdt.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/watchdog/eurotechwdt.c	Sat Apr  3 19:38:41 2004
@@ -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 = 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 @@
 #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 -Nru a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
--- a/drivers/char/watchdog/ib700wdt.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/watchdog/ib700wdt.c	Sat Apr  3 19:38:55 2004
@@ -284,8 +284,6 @@
 
 static struct notifier_block ibwdt_notifier = {
 	.notifier_call = ibwdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init ibwdt_init(void)
diff -Nru a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
--- a/drivers/char/watchdog/machzwd.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/watchdog/machzwd.c	Sat Apr  3 19:38:41 2004
@@ -447,8 +447,6 @@
  */
 static struct notifier_block zf_notifier = {
 	.notifier_call = zf_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static void __init zf_show_action(int act)
diff -Nru a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
--- a/drivers/char/watchdog/pcwd.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/watchdog/pcwd.c	Sat Apr  3 19:38:41 2004
@@ -44,10 +44,16 @@
  *              Added timeout module option to override default
  */
 
+/*
+ *	A bells and whistles driver is available from http://www.pcwd.de/
+ *	More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
+ */
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/timer.h>
+#include <linux/jiffies.h>
 #include <linux/config.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
@@ -56,6 +62,7 @@
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
+#include <linux/notifier.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/reboot.h>
@@ -63,15 +70,8 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-/*
- * These are the auto-probe addresses available.
- *
- * Revision A only uses ports 0x270 and 0x370.  Revision C introduced 0x350.
- * Revision A has an address range of 2 addresses, while Revision C has 3.
- */
-static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
-
-#define WD_VER                  "1.12 (12/14/2001)"
+#define WD_VER                  "1.16 (03/27/2004)"
+#define PFX			"pcwd: "
 
 /*
  * It should be noted that PCWD_REVISION_B was removed because A and B
@@ -83,13 +83,68 @@
 #define	PCWD_REVISION_A		1
 #define	PCWD_REVISION_C		2
 
-#define	WD_TIMEOUT		4	/* 2 seconds for a timeout */
-static int timeout_val = WD_TIMEOUT;
-static int timeout = 2;
+/*
+ * These are the defines that describe the control status bits for the
+ * PC Watchdog card, revision A.
+ */
+#define WD_WDRST                0x01	/* Previously reset state */
+#define WD_T110                 0x02	/* Temperature overheat sense */
+#define WD_HRTBT                0x04	/* Heartbeat sense */
+#define WD_RLY2                 0x08	/* External relay triggered */
+#define WD_SRLY2                0x80	/* Software external relay triggered */
+
+/*
+ * These are the defines that describe the control status bits for the
+ * PC Watchdog card, revision C.
+ */
+#define WD_REVC_WTRP            0x01	/* Watchdog Trip status */
+#define WD_REVC_HRBT            0x02	/* Watchdog Heartbeat */
+#define WD_REVC_TTRP            0x04	/* Temperature Trip status */
+
+/* max. time we give an ISA watchdog card to process a command */
+/* 500ms for each 4 bit response (according to spec.) */
+#define ISA_COMMAND_TIMEOUT     1000
+
+/* Watchdog's internal commands */
+#define CMD_ISA_IDLE                    0x00
+#define CMD_ISA_VERSION_INTEGER         0x01
+#define CMD_ISA_VERSION_TENTH           0x02
+#define CMD_ISA_VERSION_HUNDRETH        0x03
+#define CMD_ISA_VERSION_MINOR           0x04
+#define CMD_ISA_SWITCH_SETTINGS         0x05
+#define CMD_ISA_DELAY_TIME_2SECS        0x0A
+#define CMD_ISA_DELAY_TIME_4SECS        0x0B
+#define CMD_ISA_DELAY_TIME_8SECS        0x0C
+
+/*
+ * We are using an kernel timer to do the pinging of the watchdog
+ * every ~500ms. We try to set the internal heartbeat of the
+ * watchdog to 2 ms.
+ */
+
+#define WDT_INTERVAL (HZ/2+1)
+
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int cards_found;
+
+/* internal variables */
+static atomic_t open_allowed = ATOMIC_INIT(1);
 static char expect_close;
+static struct timer_list timer;
+static unsigned long next_heartbeat;
+static int temp_panic;
+static int revision;			/* The card's revision */
+static int supports_temp;		/* Wether or not the card has a temperature device */
+static int command_mode;		/* Wether or not the card is in command mode */
+static int initial_status;		/* The card's boot status */
+static int current_readport;		/* The cards I/O address */
+static spinlock_t io_lock;
 
-module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=2)");
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 60		/* 60 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
 static int nowayout = 1;
@@ -100,155 +155,261 @@
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
-
 /*
- * These are the defines for the PC Watchdog card, revision A.
+ *	Internal functions
  */
-#define WD_WDRST                0x01	/* Previously reset state */
-#define WD_T110                 0x02	/* Temperature overheat sense */
-#define WD_HRTBT                0x04	/* Heartbeat sense */
-#define WD_RLY2                 0x08	/* External relay triggered */
-#define WD_SRLY2                0x80	/* Software external relay triggered */
 
-static int current_readport, revision, temp_panic;
-static atomic_t open_allowed = ATOMIC_INIT(1);
-static int initial_status, supports_temp, mode_debug;
-static spinlock_t io_lock;
-
-/*
- * PCWD_CHECKCARD
- *
- * This routine checks the "current_readport" to see if the card lies there.
- * If it does, it returns accordingly.
- */
-static int __init pcwd_checkcard(void)
+static int send_isa_command(int cmd)
 {
-	int card_dat, prev_card_dat, found = 0, count = 0, done = 0;
-
-	card_dat = 0x00;
-	prev_card_dat = 0x00;
+	int i;
+	int control_status;
+	int port0, last_port0;	/* Double read for stabilising */
 
-	prev_card_dat = inb(current_readport);
-	if (prev_card_dat == 0xFF)
-		return 0;
+	/* The WCMD bit must be 1 and the command is only 4 bits in size */
+	control_status = (cmd & 0x0F) | 0x80;
+	outb_p(control_status, current_readport + 2);
+	udelay(ISA_COMMAND_TIMEOUT);
 
-	while(count < timeout_val) {
+	port0 = inb_p(current_readport);
+	for (i = 0; i < 25; ++i) {
+		last_port0 = port0;
+		port0 = inb_p(current_readport);
 
-	/* Read the raw card data from the port, and strip off the
-	   first 4 bits */
+		if (port0 == last_port0)
+			break;	/* Data is stable */
 
-		card_dat = inb_p(current_readport);
-		card_dat &= 0x000F;
+		udelay (250);
+	}
 
-	/* Sleep 1/2 second (or 500000 microseconds :) */
+	return port0;
+}
 
-		mdelay(500);
-		done = 0;
+static int set_command_mode(void)
+{
+	int i, found=0, count=0;
 
-	/* If there's a heart beat in both instances, then this means we
-	   found our card.  This also means that either the card was
-	   previously reset, or the computer was power-cycled. */
+	/* Set the card into command mode */
+	spin_lock(&io_lock);
+	while ((!found) && (count < 3)) {
+		i = send_isa_command(CMD_ISA_IDLE);
 
-		if ((card_dat & WD_HRTBT) && (prev_card_dat & WD_HRTBT) &&
-			(!done)) {
+		if (i == 0x00)
 			found = 1;
-			done = 1;
-			break;
+		else if (i == 0xF3) {
+			/* Card does not like what we've done to it */
+			outb_p(0x00, current_readport + 2);
+			udelay(1200);	/* Spec says wait 1ms */
+			outb_p(0x00, current_readport + 2);
+			udelay(ISA_COMMAND_TIMEOUT);
 		}
+		count++;
+	}
+	spin_unlock(&io_lock);
+	command_mode = found;
 
-	/* If the card data is exactly the same as the previous card data,
-	   it's safe to assume that we should check again.  The manual says
-	   that the heart beat will change every second (or the bit will
-	   toggle), and this can be used to see if the card is there.  If
-	   the card was powered up with a cold boot, then the card will
-	   not start blinking until 2.5 minutes after a reboot, so this
-	   bit will stay at 1. */
+	return(found);
+}
 
-		if ((card_dat == prev_card_dat) && (!done)) {
-			count++;
-			done = 1;
+static void unset_command_mode(void)
+{
+	/* Set the card into normal mode */
+	spin_lock(&io_lock);
+	outb_p(0x00, current_readport + 2);
+	udelay(ISA_COMMAND_TIMEOUT);
+	spin_unlock(&io_lock);
+
+	command_mode = 0;
+}
+
+static void pcwd_timer_ping(unsigned long data)
+{
+	int wdrst_stat;
+
+	/* If we got a heartbeat pulse within the WDT_INTERVAL
+	 * we agree to ping the WDT */
+	if(time_before(jiffies, next_heartbeat)) {
+		/* Ping the watchdog */
+		spin_lock(&io_lock);
+		if (revision == PCWD_REVISION_A) {
+			/*  Rev A cards are reset by setting the WD_WDRST bit in register 1 */
+			wdrst_stat = inb_p(current_readport);
+			wdrst_stat &= 0x0F;
+			wdrst_stat |= WD_WDRST;
+
+			outb_p(wdrst_stat, current_readport + 1);
+		} else {
+			/* Re-trigger watchdog by writing to port 0 */
+			outb_p(0x00, current_readport);
 		}
 
-	/* If the card data is toggling any bits, this means that the heart
-	   beat was detected, or something else about the card is set. */
+		/* Re-set the timer interval */
+		mod_timer(&timer, jiffies + WDT_INTERVAL);
 
-		if ((card_dat != prev_card_dat) && (!done)) {
-			done = 1;
-			found = 1;
-			break;
+		spin_unlock(&io_lock);
+	} else {
+		printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
+	}
+}
+
+static int pcwd_start(void)
+{
+	int stat_reg;
+
+	next_heartbeat = jiffies + (heartbeat * HZ);
+
+	/* Start the timer */
+	mod_timer(&timer, jiffies + WDT_INTERVAL);
+
+	/* Enable the port */
+	if (revision == PCWD_REVISION_C) {
+		spin_lock(&io_lock);
+		outb_p(0x00, current_readport + 3);
+		udelay(ISA_COMMAND_TIMEOUT);
+		stat_reg = inb_p(current_readport + 2);
+		spin_unlock(&io_lock);
+		if (stat_reg & 0x10) {
+			printk(KERN_INFO PFX "Could not start watchdog\n");
+			return -EIO;
 		}
+	}
+	return 0;
+}
+
+static int pcwd_stop(void)
+{
+	int stat_reg;
 
-	/* Otherwise something else strange happened. */
+	/* Stop the timer */
+	del_timer(&timer);
 
-		if (!done)
-			count++;
+	/*  Disable the board  */
+	if (revision == PCWD_REVISION_C) {
+		spin_lock(&io_lock);
+		outb_p(0xA5, current_readport + 3);
+		udelay(ISA_COMMAND_TIMEOUT);
+		outb_p(0xA5, current_readport + 3);
+		udelay(ISA_COMMAND_TIMEOUT);
+		stat_reg = inb_p(current_readport + 2);
+		spin_unlock(&io_lock);
+		if ((stat_reg & 0x10) == 0) {
+			printk(KERN_INFO PFX "Could not stop watchdog\n");
+			return -EIO;
+		}
 	}
+	return 0;
+}
+
+static void pcwd_keepalive(void)
+{
+	/* user land ping */
+	next_heartbeat = jiffies + (heartbeat * HZ);
+}
 
-	return((found) ? 1 : 0);
+static int pcwd_set_heartbeat(int t)
+{
+	if ((t < 2) || (t > 7200)) /* arbitrary upper limit */
+		return -EINVAL;
+
+	heartbeat = t;
+	return 0;
 }
 
-void pcwd_showprevstate(void)
+static int pcwd_get_status(int *status)
 {
-	int card_status = 0x0000;
+	int card_status;
 
+	*status=0;
+	spin_lock(&io_lock);
 	if (revision == PCWD_REVISION_A)
-		initial_status = card_status = inb(current_readport);
+		/* Rev A cards return status information from
+		 * the base register, which is used for the
+		 * temperature in other cards. */
+		card_status = inb(current_readport);
 	else {
-		initial_status = card_status = inb(current_readport + 1);
-		outb_p(0x00, current_readport + 1); /* clear reset status */
+		/* Rev C cards return card status in the base
+		 * address + 1 register. And use different bits
+		 * to indicate a card initiated reset, and an
+		 * over-temperature condition. And the reboot
+		 * status can be reset. */
+		card_status = inb(current_readport + 1);
 	}
+	spin_unlock(&io_lock);
 
 	if (revision == PCWD_REVISION_A) {
 		if (card_status & WD_WDRST)
-			printk(KERN_INFO "pcwd: Previous reboot was caused by the card.\n");
+			*status |= WDIOF_CARDRESET;
 
 		if (card_status & WD_T110) {
-			printk(KERN_EMERG "pcwd: Card senses a CPU Overheat.  Panicking!\n");
-			printk(KERN_EMERG "pcwd: CPU Overheat.\n");
-			machine_power_off();
+			*status |= WDIOF_OVERHEAT;
+			if (temp_panic) {
+				printk (KERN_INFO PFX "Temperature overheat trip!\n");
+				machine_power_off();
+			}
 		}
-
-		if ((!(card_status & WD_WDRST)) &&
-		    (!(card_status & WD_T110)))
-			printk(KERN_INFO "pcwd: Cold boot sense.\n");
 	} else {
-		if (card_status & 0x01)
-			printk(KERN_INFO "pcwd: Previous reboot was caused by the card.\n");
+		if (card_status & WD_REVC_WTRP)
+			*status |= WDIOF_CARDRESET;
 
-		if (card_status & 0x04) {
-			printk(KERN_EMERG "pcwd: Card senses a CPU Overheat.  Panicking!\n");
-			printk(KERN_EMERG "pcwd: CPU Overheat.\n");
-			machine_power_off();
+		if (card_status & WD_REVC_TTRP) {
+			*status |= WDIOF_OVERHEAT;
+			if (temp_panic) {
+				printk (KERN_INFO PFX "Temperature overheat trip!\n");
+				machine_power_off();
+			}
 		}
+	}
 
-		if ((!(card_status & 0x01)) &&
-		    (!(card_status & 0x04)))
-			printk(KERN_INFO "pcwd: Cold boot sense.\n");
+	return 0;
+}
+
+static int pcwd_clear_status(void)
+{
+	if (revision == PCWD_REVISION_C) {
+		spin_lock(&io_lock);
+		outb_p(0x00, current_readport + 1); /* clear reset status */
+		spin_unlock(&io_lock);
 	}
+	return 0;
 }
 
-static void pcwd_send_heartbeat(void)
+static int pcwd_get_temperature(int *temperature)
 {
-	int wdrst_stat;
+	/* check that port 0 gives temperature info and no command results */
+	if (command_mode)
+		return -1;
 
-	wdrst_stat = inb_p(current_readport);
-	wdrst_stat &= 0x0F;
+	*temperature = 0;
+	if (!supports_temp)
+		return -ENODEV;
 
-	wdrst_stat |= WD_WDRST;
+	/*
+	 * Convert celsius to fahrenheit, since this was
+	 * the decided 'standard' for this return value.
+	 */
+	spin_lock(&io_lock);
+	*temperature = ((inb(current_readport)) * 9 / 5) + 32;
+	spin_unlock(&io_lock);
 
-	if (revision == PCWD_REVISION_A)
-		outb_p(wdrst_stat, current_readport + 1);
-	else
-		outb_p(wdrst_stat, current_readport);
+	return 0;
 }
 
+/*
+ *	/dev/watchdog handling
+ */
+
 static int pcwd_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg)
 {
-	int cdat, rv;
-	static struct watchdog_info ident=
-	{
-		.options =		WDIOF_OVERHEAT|WDIOF_CARDRESET,
+	int rv;
+	int status;
+	int temperature;
+	int new_heartbeat;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_OVERHEAT |
+					WDIOF_CARDRESET |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE,
 		.firmware_version =	1,
 		.identity =		"PCWD",
 	};
@@ -263,86 +424,17 @@
 		return 0;
 
 	case WDIOC_GETSTATUS:
-		spin_lock(&io_lock);
-		if (revision == PCWD_REVISION_A)
-			cdat = inb(current_readport);
-		else
-			cdat = inb(current_readport + 1 );
-		spin_unlock(&io_lock);
-		rv = WDIOF_MAGICCLOSE;
-
-		if (revision == PCWD_REVISION_A)
-		{
-			if (cdat & WD_WDRST)
-				rv |= WDIOF_CARDRESET;
-
-			if (cdat & WD_T110)
-			{
-				rv |= WDIOF_OVERHEAT;
-
-				if (temp_panic) {
-					printk (KERN_INFO "pcwd: Temperature overheat trip!\n");
-					machine_power_off();
-				}
-			}
-		}
-		else
-		{
-			if (cdat & 0x01)
-				rv |= WDIOF_CARDRESET;
-
-			if (cdat & 0x04)
-			{
-				rv |= WDIOF_OVERHEAT;
-
-				if (temp_panic) {
-					printk (KERN_INFO "pcwd: Temperature overheat trip!\n");
-					machine_power_off();
-				}
-			}
-		}
-
-		if(put_user(rv, (int *) arg))
-			return -EFAULT;
-		return 0;
+		pcwd_get_status(&status);
+		return put_user(status, (int *) arg);
 
 	case WDIOC_GETBOOTSTATUS:
-		rv = 0;
+		return put_user(initial_status, (int *) arg);
 
-		if (revision == PCWD_REVISION_A)
-		{
-			if (initial_status & WD_WDRST)
-				rv |= WDIOF_CARDRESET;
-
-			if (initial_status & WD_T110)
-				rv |= WDIOF_OVERHEAT;
-		}
-		else
-		{
-			if (initial_status & 0x01)
-				rv |= WDIOF_CARDRESET;
-
-			if (initial_status & 0x04)
-				rv |= WDIOF_OVERHEAT;
-		}
-
-		if(put_user(rv, (int *) arg))
+	case WDIOC_GETTEMP:
+		if (pcwd_get_temperature(&temperature))
 			return -EFAULT;
-		return 0;
 
-	case WDIOC_GETTEMP:
-
-		rv = 0;
-		if ((supports_temp) && (mode_debug == 0))
-		{
-			spin_lock(&io_lock);
-			rv = inb(current_readport);
-			spin_unlock(&io_lock);
-			if(put_user(rv, (int*) arg))
-				return -EFAULT;
-		} else if(put_user(rv, (int*) arg))
-				return -EFAULT;
-		return 0;
+		return put_user(temperature, (int *) arg);
 
 	case WDIOC_SETOPTIONS:
 		if (revision == PCWD_REVISION_C)
@@ -352,32 +444,12 @@
 
 			if (rv & WDIOS_DISABLECARD)
 			{
-				spin_lock(&io_lock);
-				outb_p(0xA5, current_readport + 3);
-				outb_p(0xA5, current_readport + 3);
-				cdat = inb_p(current_readport + 2);
-				spin_unlock(&io_lock);
-				if ((cdat & 0x10) == 0)
-				{
-					printk(KERN_INFO "pcwd: Could not disable card.\n");
-					return -EIO;
-				}
-
-				return 0;
+				return pcwd_stop();
 			}
 
 			if (rv & WDIOS_ENABLECARD)
 			{
-				spin_lock(&io_lock);
-				outb_p(0x00, current_readport + 3);
-				cdat = inb_p(current_readport + 2);
-				spin_unlock(&io_lock);
-				if (cdat & 0x10)
-				{
-					printk(KERN_INFO "pcwd: Could not enable card.\n");
-					return -EIO;
-				}
-				return 0;
+				return pcwd_start();
 			}
 
 			if (rv & WDIOS_TEMPPANIC)
@@ -388,8 +460,21 @@
 		return -EINVAL;
 
 	case WDIOC_KEEPALIVE:
-		pcwd_send_heartbeat();
+		pcwd_keepalive();
 		return 0;
+
+	case WDIOC_SETTIMEOUT:
+		if (get_user(new_heartbeat, (int *) arg))
+			return -EFAULT;
+
+		if (pcwd_set_heartbeat(new_heartbeat))
+			return -EINVAL;
+
+		pcwd_keepalive();
+		/* Fall */
+
+	case WDIOC_GETTIMEOUT:
+		return put_user(heartbeat, (int *)arg);
 	}
 
 	return 0;
@@ -418,80 +503,130 @@
 					expect_close = 42;
 			}
 		}
-		pcwd_send_heartbeat();
+		pcwd_keepalive();
 	}
 	return len;
 }
 
-static int pcwd_open(struct inode *ino, struct file *filep)
+static int pcwd_open(struct inode *inode, struct file *file)
 {
-	switch (iminor(ino)) {
-	case WATCHDOG_MINOR:
-		if (!atomic_dec_and_test(&open_allowed) ) {
-			atomic_inc( &open_allowed );
-			return -EBUSY;
-		}
+	if (!atomic_dec_and_test(&open_allowed) ) {
+		atomic_inc( &open_allowed );
+		return -EBUSY;
+	}
+
+	if (nowayout)
 		__module_get(THIS_MODULE);
-		/*  Enable the port  */
-		if (revision == PCWD_REVISION_C) {
-			spin_lock(&io_lock);
-			outb_p(0x00, current_readport + 3);
-			spin_unlock(&io_lock);
-		}
-		return(0);
 
-	case TEMP_MINOR:
-		return(0);
-	default:
-		return (-ENODEV);
+	/* Activate */
+	pcwd_start();
+	pcwd_keepalive();
+	return(0);
+}
+
+static int pcwd_close(struct inode *inode, struct file *file)
+{
+	if (expect_close == 42) {
+		pcwd_stop();
+		atomic_inc( &open_allowed );
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		pcwd_keepalive();
 	}
+	expect_close = 0;
+	return 0;
 }
 
-static ssize_t pcwd_read(struct file *file, char *buf, size_t count,
+/*
+ *	/dev/temperature handling
+ */
+
+static ssize_t pcwd_temp_read(struct file *file, char *buf, size_t count,
 			 loff_t *ppos)
 {
-	unsigned short c;
-	unsigned char cp;
+	int temperature;
 
-	/*  Can't seek (pread) on this device  */
+	/* Can't seek (pread) on this device */
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
-	switch(iminor(file->f_dentry->d_inode))
-	{
-		case TEMP_MINOR:
-			/*
-			 * Convert metric to Fahrenheit, since this was
-			 * the decided 'standard' for this return value.
-			 */
-
-			c = inb(current_readport);
-			cp = (c * 9 / 5) + 32;
-			if(copy_to_user(buf, &cp, 1))
-				return -EFAULT;
-			return 1;
-		default:
-			return -EINVAL;
-	}
+
+	if (pcwd_get_temperature(&temperature))
+		return -EFAULT;
+
+	if (copy_to_user(buf, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
 }
 
-static int pcwd_close(struct inode *ino, struct file *filep)
+static int pcwd_temp_open(struct inode *inode, struct file *file)
 {
-	if (iminor(ino)==WATCHDOG_MINOR) {
-		if (expect_close == 42) {
-			/*  Disable the board  */
-			if (revision == PCWD_REVISION_C) {
-				spin_lock(&io_lock);
-				outb_p(0xA5, current_readport + 3);
-				outb_p(0xA5, current_readport + 3);
-				spin_unlock(&io_lock);
-			}
-			atomic_inc( &open_allowed );
-		}
-	}
-	expect_close = 0;
+	if (!supports_temp)
+		return -ENODEV;
+
 	return 0;
 }
 
+static int pcwd_temp_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	Notify system
+ */
+
+static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		pcwd_stop();
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations pcwd_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= pcwd_write,
+	.ioctl		= pcwd_ioctl,
+	.open		= pcwd_open,
+	.release	= pcwd_close,
+};
+
+static struct miscdevice pcwd_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&pcwd_fops,
+};
+
+static struct file_operations pcwd_temp_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= pcwd_temp_read,
+	.open		= pcwd_temp_open,
+	.release	= pcwd_temp_close,
+};
+
+static struct miscdevice temp_miscdev = {
+	.minor =	TEMP_MINOR,
+	.name =		"temperature",
+	.fops =		&pcwd_temp_fops,
+};
+
+static struct notifier_block pcwd_notifier = {
+	.notifier_call =	pcwd_notify_sys,
+};
+
+/*
+ *	Init & exit routines
+ */
+
 static inline void get_support(void)
 {
 	if (inb(current_readport) != 0xF0)
@@ -503,6 +638,8 @@
 	int r = PCWD_REVISION_C;
 
 	spin_lock(&io_lock);
+	/* REV A cards use only 2 io ports; test
+	 * presumes a floating bus reads as 0xff. */
 	if ((inb(current_readport + 2) == 0xFF) ||
 	    (inb(current_readport + 3) == 0xFF))
 		r=PCWD_REVISION_A;
@@ -511,199 +648,283 @@
 	return r;
 }
 
-static int __init send_command(int cmd)
-{
-	int i;
-
-	outb_p(cmd, current_readport + 2);
-	mdelay(1);
-
-	i = inb(current_readport);
-	i = inb(current_readport);
-
-	return(i);
-}
-
 static inline char *get_firmware(void)
 {
-	int i, found = 0, count = 0, one, ten, hund, minor;
+	int one, ten, hund, minor;
 	char *ret;
 
 	ret = kmalloc(6, GFP_KERNEL);
 	if(ret == NULL)
 		return NULL;
 
-	while((count < 3) && (!found)) {
-		outb_p(0x80, current_readport + 2);
-		i = inb(current_readport);
-
-		if (i == 0x00)
-			found = 1;
-		else if (i == 0xF3)
-			outb_p(0x00, current_readport + 2);
-
-		udelay(400L);
-		count++;
-	}
-
-	if (found) {
-		mode_debug = 1;
-
-		one = send_command(0x81);
-		ten = send_command(0x82);
-		hund = send_command(0x83);
-		minor = send_command(0x84);
+	if (set_command_mode()) {
+		one = send_isa_command(CMD_ISA_VERSION_INTEGER);
+		ten = send_isa_command(CMD_ISA_VERSION_TENTH);
+		hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
+		minor = send_isa_command(CMD_ISA_VERSION_MINOR);
 		sprintf(ret, "%c.%c%c%c", one, ten, hund, minor);
 	}
 	else
 		sprintf(ret, "ERROR");
 
+	unset_command_mode();
 	return(ret);
 }
 
-static void debug_off(void)
+static inline int get_option_switches(void)
 {
-	outb_p(0x00, current_readport + 2);
-	mode_debug = 0;
-}
-
-static struct file_operations pcwd_fops = {
-	.owner		= THIS_MODULE,
-	.read		= pcwd_read,
-	.write		= pcwd_write,
-	.ioctl		= pcwd_ioctl,
-	.open		= pcwd_open,
-	.release	= pcwd_close,
-};
+	int rv=0;
 
-static struct miscdevice pcwd_miscdev = {
-	.minor =	WATCHDOG_MINOR,
-	.name =		"watchdog",
-	.fops =		&pcwd_fops,
-};
-
-static struct miscdevice temp_miscdev = {
-	.minor =	TEMP_MINOR,
-	.name =		"temperature",
-	.fops =		&pcwd_fops,
-};
+	if (set_command_mode()) {
+		/* Get switch settings */
+		rv = send_isa_command(CMD_ISA_SWITCH_SETTINGS);
+	}
 
-static void __init pcwd_validate_timeout(void)
-{
-	timeout_val = timeout * 2;
+	unset_command_mode();
+	return(rv);
 }
 
-static int __init pcwatchdog_init(void)
+static int __devinit pcwatchdog_init(int base_addr)
 {
+	int ret;
 	char *firmware;
-	int i, found = 0;
-	pcwd_validate_timeout();
-	spin_lock_init(&io_lock);
+	int option_switches;
+
+	cards_found++;
+	if (cards_found == 1)
+		printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
+
+	if (cards_found > 1) {
+		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		return -ENODEV;
+	}
 
-	revision = PCWD_REVISION_A;
+	if (base_addr == 0x0000) {
+		printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+		return -ENODEV;
+	}
+	current_readport = base_addr;
 
-	printk(KERN_INFO "pcwd: v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
+	/* Check card's revision */
+	revision = get_revision();
+
+	if (!request_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
+		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			current_readport);
+		current_readport = 0x0000;
+		return -EIO;
+	}
 
 	/* Initial variables */
 	supports_temp = 0;
-	mode_debug = 0;
 	temp_panic = 0;
 	initial_status = 0x0000;
 
-#ifndef	PCWD_BLIND
-	for (i = 0; pcwd_ioports[i] != 0; i++) {
-		current_readport = pcwd_ioports[i];
+	/* get the boot_status */
+	pcwd_get_status(&initial_status);
 
-		if (pcwd_checkcard()) {
-			found = 1;
-			break;
-		}
-	}
+	/* clear the "card caused reboot" flag */
+	pcwd_clear_status();
 
-	if (!found) {
-		printk(KERN_INFO "pcwd: No card detected, or port not available.\n");
-		return(-EIO);
-	}
-#endif
+	init_timer(&timer);
+	timer.function = pcwd_timer_ping;
+	timer.data = 0;
 
-#ifdef	PCWD_BLIND
-	current_readport = PCWD_BLIND;
-#endif
+	/*  Disable the board  */
+	pcwd_stop();
 
+	/*  Check whether or not the card supports the temperature device */
 	get_support();
-	revision = get_revision();
 
+	/* Get some extra info from the hardware (in command/debug/diag mode) */
 	if (revision == PCWD_REVISION_A)
-		printk(KERN_INFO "pcwd: PC Watchdog (REV.A) detected at port 0x%03x\n", current_readport);
+		printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", current_readport);
 	else if (revision == PCWD_REVISION_C) {
 		firmware = get_firmware();
-		printk(KERN_INFO "pcwd: PC Watchdog (REV.C) detected at port 0x%03x (Firmware version: %s)\n",
+		printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
 			current_readport, firmware);
 		kfree(firmware);
+		option_switches = get_option_switches();
+		printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
+			option_switches,
+			((option_switches & 0x10) ? "ON" : "OFF"),
+			((option_switches & 0x08) ? "ON" : "OFF"));
+
+		/* Reprogram internal heartbeat to 2 seconds */
+		if (set_command_mode()) {
+			send_isa_command(CMD_ISA_DELAY_TIME_2SECS);
+			unset_command_mode();
+		}
 	} else {
 		/* Should NEVER happen, unless get_revision() fails. */
-		printk("pcwd: Unable to get revision.\n");
+		printk(KERN_INFO PFX "Unable to get revision\n");
+		release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+		current_readport = 0x0000;
 		return -1;
 	}
 
 	if (supports_temp)
-		printk(KERN_INFO "pcwd: Temperature Option Detected.\n");
-
-	debug_off();
+		printk(KERN_INFO PFX "Temperature Option Detected\n");
 
-	pcwd_showprevstate();
+	if (initial_status & WDIOF_CARDRESET)
+		printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
 
-	/*  Disable the board  */
-	if (revision == PCWD_REVISION_C) {
-		outb_p(0xA5, current_readport + 3);
-		outb_p(0xA5, current_readport + 3);
+	if (initial_status & WDIOF_OVERHEAT) {
+		printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");
+		printk(KERN_EMERG PFX "CPU Overheat\n");
 	}
 
-	if (misc_register(&pcwd_miscdev))
-		return -ENODEV;
+	if (initial_status == 0)
+		printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
 
-	if (supports_temp)
-		if (misc_register(&temp_miscdev)) {
-			misc_deregister(&pcwd_miscdev);
-			return -ENODEV;
-		}
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+        if (pcwd_set_heartbeat(heartbeat)) {
+                pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
+                printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n",
+                        WATCHDOG_HEARTBEAT);
+	}
 
+	ret = register_reboot_notifier(&pcwd_notifier);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+		current_readport = 0x0000;
+		return ret;
+	}
 
-	if (revision == PCWD_REVISION_A) {
-		if (!request_region(current_readport, 2, "PCWD Rev.A (Berkshire)")) {
-			misc_deregister(&pcwd_miscdev);
-			if (supports_temp)
-				misc_deregister(&pcwd_miscdev);
-			return -EIO;
+	if (supports_temp) {
+		ret = misc_register(&temp_miscdev);
+		if (ret) {
+			printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+				TEMP_MINOR, ret);
+			unregister_reboot_notifier(&pcwd_notifier);
+			release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+			current_readport = 0x0000;
+			return ret;
 		}
 	}
-	else
-		if (!request_region(current_readport, 4, "PCWD Rev.C (Berkshire)")) {
-			misc_deregister(&pcwd_miscdev);
-			if (supports_temp)
-				misc_deregister(&pcwd_miscdev);
-			return -EIO;
-		}
+
+	ret = misc_register(&pcwd_miscdev);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		if (supports_temp)
+			misc_deregister(&temp_miscdev);
+		unregister_reboot_notifier(&pcwd_notifier);
+		release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+		current_readport = 0x0000;
+		return ret;
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
 
 	return 0;
 }
 
-static void __exit pcwatchdog_exit(void)
+static void __devexit pcwatchdog_exit(void)
 {
-	misc_deregister(&pcwd_miscdev);
 	/*  Disable the board  */
-	if (revision == PCWD_REVISION_C) {
-		outb_p(0xA5, current_readport + 3);
-		outb_p(0xA5, current_readport + 3);
-	}
+	if (!nowayout)
+		pcwd_stop();
+
+	/* Deregister */
+	misc_deregister(&pcwd_miscdev);
 	if (supports_temp)
 		misc_deregister(&temp_miscdev);
-
+	unregister_reboot_notifier(&pcwd_notifier);
 	release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
+	current_readport = 0x0000;
+}
+
+/*
+ *  The ISA cards have a heartbeat bit in one of the registers, which
+ *  register is card dependent.  The heartbeat bit is monitored, and if
+ *  found, is considered proof that a Berkshire card has been found.
+ *  The initial rate is once per second at board start up, then twice
+ *  per second for normal operation.
+ */
+static int __init pcwd_checkcard(int base_addr)
+{
+	int port0, last_port0;	/* Reg 0, in case it's REV A */
+	int port1, last_port1;	/* Register 1 for REV C cards */
+	int i;
+	int retval;
+
+	if (!request_region (base_addr, 4, "PCWD")) {
+		printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
+		return 0;
+	}
+
+	retval = 0;
+
+	port0 = inb_p(base_addr);	/* For REV A boards */
+	port1 = inb_p(base_addr + 1);	/* For REV C boards */
+	if (port0 != 0xff || port1 != 0xff) {
+		/* Not an 'ff' from a floating bus, so must be a card! */
+		for (i = 0; i < 4; ++i) {
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(HZ / 2);
+
+			last_port0 = port0;
+			last_port1 = port1;
+
+			port0 = inb_p(base_addr);
+			port1 = inb_p(base_addr + 1);
+
+			/* Has either hearbeat bit changed?  */
+			if ((port0 ^ last_port0) & WD_HRTBT ||
+			    (port1 ^ last_port1) & WD_REVC_HRBT) {
+				retval = 1;
+				break;
+			}
+		}
+	}
+	release_region (base_addr, 4);
+
+	return retval;
+}
+
+/*
+ * These are the auto-probe addresses available.
+ *
+ * Revision A only uses ports 0x270 and 0x370.  Revision C introduced 0x350.
+ * Revision A has an address range of 2 addresses, while Revision C has 4.
+ */
+static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
+
+static int __init pcwd_init_module(void)
+{
+	int i, found = 0;
+
+	spin_lock_init(&io_lock);
+
+	for (i = 0; pcwd_ioports[i] != 0; i++) {
+		if (pcwd_checkcard(pcwd_ioports[i])) {
+			if (!(pcwatchdog_init(pcwd_ioports[i])))
+				found++;
+		}
+	}
+
+	if (!found) {
+		printk (KERN_INFO PFX "No card detected, or port not available\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit pcwd_cleanup_module(void)
+{
+	if (current_readport)
+		pcwatchdog_exit();
+	return;
 }
 
-module_init(pcwatchdog_init);
-module_exit(pcwatchdog_exit);
+module_init(pcwd_init_module);
+module_exit(pcwd_cleanup_module);
 
 MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>");
 MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
diff -Nru a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
--- a/drivers/char/watchdog/pcwd_pci.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/watchdog/pcwd_pci.c	Sat Apr  3 19:38:41 2004
@@ -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 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 @@
 
 	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 @@
 	unregister_reboot_notifier(&pcipcwd_notifier);
 	pci_release_regions(pdev);
 	pci_disable_device(pdev);
+	cards_found--;
 }
 
 static struct pci_device_id pcipcwd_pci_tbl[] = {
diff -Nru a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
--- a/drivers/char/watchdog/pcwd_usb.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/watchdog/pcwd_usb.c	Sat Apr  3 19:38:42 2004
@@ -589,7 +589,7 @@
 	}
 
 	/* 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 -Nru a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
--- a/drivers/char/watchdog/sbc60xxwdt.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/char/watchdog/sbc60xxwdt.c	Sat Apr  3 19:38:45 2004
@@ -322,8 +322,6 @@
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static void __exit sbc60xxwdt_unload(void)
diff -Nru a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
--- a/drivers/char/watchdog/sc1200wdt.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/char/watchdog/sc1200wdt.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 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 = 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)");
 
 
@@ -453,32 +454,6 @@
 #endif
 	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 -Nru a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
--- a/drivers/char/watchdog/sc520_wdt.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/char/watchdog/sc520_wdt.c	Sat Apr  3 19:38:43 2004
@@ -354,8 +354,6 @@
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static void __exit sc520_wdt_unload(void)
diff -Nru a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
--- a/drivers/char/watchdog/shwdt.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/char/watchdog/shwdt.c	Sat Apr  3 19:38:42 2004
@@ -412,7 +412,7 @@
 		return rc;
 	}
 
-	rc = misc_register(&sh_wdt_miscdev)
+	rc = misc_register(&sh_wdt_miscdev);
 	if (rc) {
 		printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n",
 			sh_wdt_miscdev.minor, rc);
diff -Nru a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
--- a/drivers/char/watchdog/softdog.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/char/watchdog/softdog.c	Sat Apr  3 19:38:43 2004
@@ -1,5 +1,5 @@
 /*
- *	SoftDog	0.06:	A Software Watchdog Device
+ *	SoftDog	0.07:	A Software Watchdog Device
  *
  *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
  *				http://www.redhat.com
@@ -40,26 +40,21 @@
 #include <linux/moduleparam.h>
 #include <linux/config.h>
 #include <linux/types.h>
+#include <linux/timer.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/fs.h>
+#include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
 
-#define TIMER_MARGIN	60		/* (secs) Default is 1 minute */
+#define PFX "SoftDog: "
 
-static char expect_close;
+#define TIMER_MARGIN	60		/* Default is 60 seconds */
 static int soft_margin = TIMER_MARGIN;	/* in seconds */
-#ifdef ONLY_TESTING
-static int soft_noboot = 1;
-#else
-static int soft_noboot = 0;
-#endif  /* ONLY_TESTING */
-
 module_param(soft_margin, int, 0);
-module_param(soft_noboot, int, 0);
-MODULE_LICENSE("GPL");
+MODULE_PARM_DESC(soft_margin, "Watchdog soft_margin in seconds. (0<soft_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
 static int nowayout = 1;
@@ -70,6 +65,15 @@
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
+#ifdef ONLY_TESTING
+static int soft_noboot = 1;
+#else
+static int soft_noboot = 0;
+#endif  /* ONLY_TESTING */
+
+module_param(soft_noboot, int, 0);
+MODULE_PARM_DESC(soft_noboot, "Softdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
+
 /*
  *	Our timer
  */
@@ -79,6 +83,7 @@
 static struct timer_list watchdog_ticktock =
 		TIMER_INITIALIZER(watchdog_fire, 0, 0);
 static unsigned long timer_alive;
+static char expect_close;
 
 
 /*
@@ -88,17 +93,42 @@
 static void watchdog_fire(unsigned long data)
 {
 	if (soft_noboot)
-		printk(KERN_CRIT "SOFTDOG: Triggered - Reboot ignored.\n");
+		printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
 	else
 	{
-		printk(KERN_CRIT "SOFTDOG: Initiating system reboot.\n");
+		printk(KERN_CRIT PFX "Initiating system reboot.\n");
 		machine_restart(NULL);
-		printk("SOFTDOG: Reboot didn't ?????\n");
+		printk(KERN_CRIT PFX "Reboot didn't ?????\n");
 	}
 }
 
 /*
- *	Allow only one person to hold it open
+ *	Softdog operations
+ */
+
+static int softdog_keepalive(void)
+{
+	mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+	return 0;
+}
+
+static int softdog_stop(void)
+{
+	del_timer(&watchdog_ticktock);
+	return 0;
+}
+
+static int softdog_set_heartbeat(int t)
+{
+	if ((t < 0x0001) || (t > 0xFFFF))
+		return -EINVAL;
+
+	soft_margin = t;
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
  */
 
 static int softdog_open(struct inode *inode, struct file *file)
@@ -110,7 +140,7 @@
 	/*
 	 *	Activate timer
 	 */
-	mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+	softdog_keepalive();
 	return 0;
 }
 
@@ -121,9 +151,10 @@
 	 * 	Lock it in if it's a module and we set nowayout
 	 */
 	if (expect_close == 42) {
-		del_timer(&watchdog_ticktock);
+		softdog_stop();
 	} else {
-		printk(KERN_CRIT "SOFTDOG: WDT device closed unexpectedly.  WDT will not stop!\n");
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		softdog_keepalive();
 	}
 	clear_bit(0, &timer_alive);
 	expect_close = 0;
@@ -155,7 +186,7 @@
 					expect_close = 42;
 			}
 		}
-		mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+		softdog_keepalive();
 	}
 	return len;
 }
@@ -165,37 +196,57 @@
 {
 	int new_margin;
 	static struct watchdog_info ident = {
-		.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
-		.identity = "Software Watchdog",
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	0,
+		.identity =		"Software Watchdog",
 	};
 	switch (cmd) {
 		default:
 			return -ENOIOCTLCMD;
 		case WDIOC_GETSUPPORT:
-			if(copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
-				return -EFAULT;
-			return 0;
+			return copy_to_user((struct watchdog_info *)arg, &ident,
+				sizeof(ident)) ? -EFAULT : 0;
 		case WDIOC_GETSTATUS:
 		case WDIOC_GETBOOTSTATUS:
 			return put_user(0,(int *)arg);
 		case WDIOC_KEEPALIVE:
-			mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+			softdog_keepalive();
 			return 0;
 		case WDIOC_SETTIMEOUT:
 			if (get_user(new_margin, (int *)arg))
 				return -EFAULT;
-			if (new_margin < 1)
+			if (softdog_set_heartbeat(new_margin))
 				return -EINVAL;
-			soft_margin = new_margin;
-			mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
+			softdog_keepalive();
 			/* Fall */
 		case WDIOC_GETTIMEOUT:
 			return put_user(soft_margin, (int *)arg);
 	}
 }
 
+/*
+ *	Notifier for system down
+ */
+
+static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		softdog_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
 static struct file_operations softdog_fops = {
 	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
 	.write		= softdog_write,
 	.ioctl		= softdog_ioctl,
 	.open		= softdog_open,
@@ -208,18 +259,39 @@
 	.fops		= &softdog_fops,
 };
 
-static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.06, soft_margin: %d sec, nowayout: %d\n";
+static struct notifier_block softdog_notifier = {
+	.notifier_call	= softdog_notify_sys,
+};
+
+static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 initialized. soft_noboot=%d soft_margin=%d sec (nowayout= %d)\n";
 
 static int __init watchdog_init(void)
 {
 	int ret;
 
-	ret = misc_register(&softdog_miscdev);
+	/* Check that the soft_margin value is within it's range ; if not reset to the default */
+	if (softdog_set_heartbeat(soft_margin)) {
+		softdog_set_heartbeat(TIMER_MARGIN);
+		printk(KERN_INFO PFX "soft_margin value must be 0<soft_margin<65536, using %d\n",
+			TIMER_MARGIN);
+	}
 
-	if (ret)
+	ret = register_reboot_notifier(&softdog_notifier);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
 		return ret;
+	}
+
+	ret = misc_register(&softdog_miscdev);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		unregister_reboot_notifier(&softdog_notifier);
+		return ret;
+	}
 
-	printk(banner, soft_margin, nowayout);
+	printk(banner, soft_noboot, soft_margin, nowayout);
 
 	return 0;
 }
@@ -227,6 +299,7 @@
 static void __exit watchdog_exit(void)
 {
 	misc_deregister(&softdog_miscdev);
+	unregister_reboot_notifier(&softdog_notifier);
 }
 
 module_init(watchdog_init);
diff -Nru a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
--- a/drivers/char/watchdog/w83627hf_wdt.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/char/watchdog/w83627hf_wdt.c	Sat Apr  3 19:38:43 2004
@@ -257,8 +257,6 @@
 
 static struct notifier_block wdt_notifier = {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init
diff -Nru a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c
--- a/drivers/char/watchdog/w83877f_wdt.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/char/watchdog/w83877f_wdt.c	Sat Apr  3 19:38:44 2004
@@ -341,8 +341,6 @@
 static struct notifier_block wdt_notifier=
 {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static void __exit w83877f_wdt_unload(void)
diff -Nru a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
--- a/drivers/char/watchdog/wafer5823wdt.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/watchdog/wafer5823wdt.c	Sat Apr  3 19:38:55 2004
@@ -252,8 +252,6 @@
 
 static struct notifier_block wafwdt_notifier = {
 	.notifier_call = wafwdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init wafwdt_init(void)
diff -Nru a/drivers/char/watchdog/wd501p.h b/drivers/char/watchdog/wd501p.h
--- a/drivers/char/watchdog/wd501p.h	Sat Apr  3 19:38:44 2004
+++ b/drivers/char/watchdog/wd501p.h	Sat Apr  3 19:38:44 2004
@@ -1,5 +1,5 @@
 /*
- *	Industrial Computer Source WDT500/501 driver for Linux 1.3.x
+ *	Industrial Computer Source WDT500/501 driver
  *
  *	(c) Copyright 1995	CymruNET Ltd
  *				Innovation Centre
@@ -40,52 +40,13 @@
 /* programmable outputs: */
 #define WDT_PROGOUT		(io+15)	/* wr=enable, rd=disable */
 
-#define WDC_SR_WCCR		1	/* Active low */
-#define WDC_SR_TGOOD		2
-#define WDC_SR_ISOI0		4
-#define WDC_SR_ISII1		8
-#define WDC_SR_FANGOOD		16
-#define WDC_SR_PSUOVER		32	/* Active low */
-#define WDC_SR_PSUUNDR		64	/* Active low */
-#define WDC_SR_IRQ		128	/* Active low */
+								/* FAN 501 500 */
+#define WDC_SR_WCCR		1	/* Active low */	/*  X   X   X  */
+#define WDC_SR_TGOOD		2				/*  X   X   -  */
+#define WDC_SR_ISOI0		4				/*  X   X   X  */
+#define WDC_SR_ISII1		8				/*  X   X   X  */
+#define WDC_SR_FANGOOD		16				/*  X   -   -  */
+#define WDC_SR_PSUOVER		32	/* Active low */	/*  X   X   -  */
+#define WDC_SR_PSUUNDR		64	/* Active low */	/*  X   X   -  */
+#define WDC_SR_IRQ		128	/* Active low */	/*  X   X   X  */
 
-#ifndef WDT_IS_PCI
-
-/*
- *	Feature Map 1 is the active high inputs not supported on your card.
- *	Feature Map 2 is the active low inputs not supported on your card.
- */
- 
-#ifdef CONFIG_WDT_501		/* Full board */
-
-#ifdef CONFIG_WDT501_FAN	/* Full board, Fan has no tachometer */
-#define FEATUREMAP1		0
-#define WDT_OPTION_MASK		(WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT)
-#else
-#define FEATUREMAP1		WDC_SR_FANGOOD
-#define WDT_OPTION_MASK		(WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER|WDIOF_EXTERN1|WDIOF_EXTERN2)
-#endif
-
-#define FEATUREMAP2		0
-#endif
-
-#ifndef CONFIG_WDT_501
-#define CONFIG_WDT_500
-#endif
-
-#ifdef CONFIG_WDT_500		/* Minimal board */
-#define FEATUREMAP1		(WDC_SR_TGOOD|WDC_SR_FANGOOD)
-#define FEATUREMAP2		(WDC_SR_PSUOVER|WDC_SR_PSUUNDR)
-#define WDT_OPTION_MASK		(WDIOF_OVERHEAT)
-#endif
-
-#else
-
-#define FEATUREMAP1		(WDC_SR_TGOOD|WDC_SR_FANGOOD)
-#define FEATUREMAP2		(WDC_SR_PSUOVER|WDC_SR_PSUUNDR)
-#define WDT_OPTION_MASK		(WDIOF_OVERHEAT)
-#endif
-
-#ifndef FEATUREMAP1
-#error "Config option not set"
-#endif
diff -Nru a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c
--- a/drivers/char/watchdog/wdt.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/char/watchdog/wdt.c	Sat Apr  3 19:38:43 2004
@@ -1,5 +1,5 @@
 /*
- *	Industrial Computer Source WDT500/501 driver for Linux 2.1.x
+ *	Industrial Computer Source WDT500/501 driver
  *
  *	(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
  *				http://www.redhat.com
@@ -15,7 +15,7 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
- *	Release 0.09.
+ *	Release 0.10.
  *
  *	Fixes
  *		Dave Gregorich	:	Modularisation and minor bugs
@@ -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>
@@ -52,17 +53,15 @@
 static char expect_close;
 
 /*
- *	You must set these - there is no sane way to probe for this board.
- *	You can use wdt=x,y to set these now.
+ *	Module parameters
  */
 
-static int io=0x240;
-static int irq=11;
+#define WD_TIMO 60			/* Default heartbeat = 60 seconds */
 
-/* Default margin */
-#define WD_TIMO (100*60)		/* 1 minute */
-
-static int wd_margin = WD_TIMO;
+static int heartbeat = WD_TIMO;
+static int wd_heartbeat;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
 static int nowayout = 1;
@@ -70,45 +69,26 @@
 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 */
+/* You must set these - there is no sane way to probe for this board. */
+static int io=0x240;
+static int irq=11;
 
-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)");
 
+#ifdef CONFIG_WDT_501
+/* Support for the Fan Tachometer on the WDT501-P */
+static int tachometer;
+
+module_param(tachometer, int, 0);
+MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, default=0)");
+#endif /* CONFIG_WDT_501 */
+
 /*
  *	Programming support
  */
@@ -127,13 +107,77 @@
 	outb_p(val>>8, WDT_COUNT0+ctr);
 }
 
-/*
- *	Kernel methods.
+/**
+ *	wdt_start:
+ *
+ *	Start the watchdog driver.
+ */
+
+static int wdt_start(void)
+{
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdt_ctr_mode(0,3);		/* Program CTR0 for Mode 3: Square Wave Generator */
+	wdt_ctr_mode(1,2);		/* Program CTR1 for Mode 2: Rate Generator */
+	wdt_ctr_mode(2,0);		/* Program CTR2 for Mode 0: Pulse on Terminal Count */
+	wdt_ctr_load(0, 8948);		/* Count at 100Hz */
+	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
+	wdt_ctr_load(2,65535);		/* Length of reset pulse */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+	return 0;
+}
+
+/**
+ *	wdt_stop:
+ *
+ *	Stop the watchdog driver.
  */
 
+static int wdt_stop (void)
+{
+	/* Turn the card off */
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdt_ctr_load(2,0);		/* 0 length reset pulses now */
+	return 0;
+}
 
 /**
- *	wdt_status:
+ *	wdt_ping:
+ *
+ *	Reload counter one with the watchdog heartbeat. We don't bother reloading
+ *	the cascade counter.
+ */
+
+static int wdt_ping(void)
+{
+	/* Write a watchdog value */
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdt_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2: Rate Generator */
+	wdt_ctr_load(1,wd_heartbeat);	/* Heartbeat */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+	return 0;
+}
+
+/**
+ *	wdt_set_heartbeat:
+ *	@t:		the new heartbeat value that needs to be set.
+ *
+ *	Set a new heartbeat value for the watchdog device. If the heartbeat value is
+ *	incorrect we keep the old value and return -EINVAL. If successfull we
+ *	return 0.
+ */
+static int wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 65535))
+		return -EINVAL;
+
+	heartbeat = t;
+	wd_heartbeat = t * 100;
+	return 0;
+}
+
+/**
+ *	wdt_get_status:
+ *	@status:		the new status.
  *
  *	Extract the status information from a WDT watchdog device. There are
  *	several board variants so we have to know which bits are valid. Some
@@ -142,31 +186,46 @@
  *	we then map the bits onto the status ioctl flags.
  */
 
-static int wdt_status(void)
+static int wdt_get_status(int *status)
 {
-	/*
-	 *	Status register to bit flags
-	 */
+	unsigned char new_status=inb_p(WDT_SR);
 
-	int flag=0;
-	unsigned char status=inb_p(WDT_SR);
-	status|=FEATUREMAP1;
-	status&=~FEATUREMAP2;
+	*status=0;
+	if (new_status & WDC_SR_ISOI0)
+		*status |= WDIOF_EXTERN1;
+	if (new_status & WDC_SR_ISII1)
+		*status |= WDIOF_EXTERN2;
+#ifdef CONFIG_WDT_501
+	if (!(new_status & WDC_SR_TGOOD))
+		*status |= WDIOF_OVERHEAT;
+	if (!(new_status & WDC_SR_PSUOVER))
+		*status |= WDIOF_POWEROVER;
+	if (!(new_status & WDC_SR_PSUUNDR))
+		*status |= WDIOF_POWERUNDER;
+	if (tachometer) {
+		if (!(new_status & WDC_SR_FANGOOD))
+			*status |= WDIOF_FANFAULT;
+	}
+#endif /* CONFIG_WDT_501 */
+	return 0;
+}
 
-	if(!(status&WDC_SR_TGOOD))
-		flag|=WDIOF_OVERHEAT;
-	if(!(status&WDC_SR_PSUOVER))
-		flag|=WDIOF_POWEROVER;
-	if(!(status&WDC_SR_PSUUNDR))
-		flag|=WDIOF_POWERUNDER;
-	if(!(status&WDC_SR_FANGOOD))
-		flag|=WDIOF_FANFAULT;
-	if(status&WDC_SR_ISOI0)
-		flag|=WDIOF_EXTERN1;
-	if(status&WDC_SR_ISII1)
-		flag|=WDIOF_EXTERN2;
-	return flag;
+#ifdef CONFIG_WDT_501
+/**
+ *	wdt_get_temperature:
+ *
+ *	Reports the temperature in degrees Fahrenheit. The API is in
+ *	farenheit. It was designed by an imperial measurement luddite.
+ */
+
+static int wdt_get_temperature(int *temperature)
+{
+	unsigned short c=inb_p(WDT_RT);
+
+	*temperature = (c * 11 / 15) + 7;
+	return 0;
 }
+#endif /* CONFIG_WDT_501 */
 
 /**
  *	wdt_interrupt:
@@ -185,23 +244,23 @@
 	 *	Read the status register see what is up and
 	 *	then printk it.
 	 */
-
 	unsigned char status=inb_p(WDT_SR);
 
-	status|=FEATUREMAP1;
-	status&=~FEATUREMAP2;
-
 	printk(KERN_CRIT "WDT status %d\n", status);
 
-	if(!(status&WDC_SR_TGOOD))
+#ifdef CONFIG_WDT_501
+	if (!(status & WDC_SR_TGOOD))
 		printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
-	if(!(status&WDC_SR_PSUOVER))
+	if (!(status & WDC_SR_PSUOVER))
 		printk(KERN_CRIT "PSU over voltage.\n");
-	if(!(status&WDC_SR_PSUUNDR))
+	if (!(status & WDC_SR_PSUUNDR))
 		printk(KERN_CRIT "PSU under voltage.\n");
-	if(!(status&WDC_SR_FANGOOD))
-		printk(KERN_CRIT "Possible fan fault.\n");
-	if(!(status&WDC_SR_WCCR))
+	if (tachometer) {
+		if (!(status & WDC_SR_FANGOOD))
+			printk(KERN_CRIT "Possible fan fault.\n");
+	}
+#endif /* CONFIG_WDT_501 */
+	if (!(status & WDC_SR_WCCR))
 #ifdef SOFTWARE_REBOOT
 #ifdef ONLY_TESTING
 		printk(KERN_CRIT "Would Reboot.\n");
@@ -217,22 +276,6 @@
 
 
 /**
- *	wdt_ping:
- *
- *	Reload counter one with the watchdog timeout. We don't bother reloading
- *	the cascade counter.
- */
-
-static void wdt_ping(void)
-{
-	/* Write a watchdog value */
-	inb_p(WDT_DC);
-	wdt_ctr_mode(1,2);
-	wdt_ctr_load(1,wd_margin);		/* Timeout */
-	outb_p(0, WDT_DC);
-}
-
-/**
  *	wdt_write:
  *	@file: file handle to the watchdog
  *	@buf: buffer to write (unused as data does not matter here
@@ -270,40 +313,6 @@
 }
 
 /**
- *	wdt_read:
- *	@file: file handle to the watchdog board
- *	@buf: buffer to write 1 byte into
- *	@count: length of buffer
- *	@ptr: offset (no seek allowed)
- *
- *	Read reports the temperature in degrees Fahrenheit. The API is in
- *	farenheit. It was designed by an imperial measurement luddite.
- */
-
-static ssize_t wdt_read(struct file *file, char *buf, size_t count, loff_t *ptr)
-{
-	unsigned short c=inb_p(WDT_RT);
-	unsigned char cp;
-
-	/*  Can't seek (pread) on this device  */
-	if (ptr != &file->f_pos)
-		return -ESPIPE;
-
-	switch(iminor(file->f_dentry->d_inode))
-	{
-		case TEMP_MINOR:
-			c*=11;
-			c/=15;
-			cp=c+7;
-			if(copy_to_user(buf,&cp,1))
-				return -EFAULT;
-			return 1;
-		default:
-			return -EINVAL;
-	}
-}
-
-/**
  *	wdt_ioctl:
  *	@inode: inode of the device
  *	@file: file handle to the device
@@ -318,18 +327,25 @@
 static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	unsigned long arg)
 {
-	int new_margin;
+	int new_heartbeat;
+	int status;
 
-	static struct watchdog_info ident=
-	{
-		.options = WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER
-					|WDIOF_EXTERN1|WDIOF_EXTERN2|WDIOF_FANFAULT
-					|WDIOF_SETTIMEOUT|WDIOF_MAGICCLOSE,
-		.firmware_version = 1,
-		.identity = "WDT500/501",
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT|
+					WDIOF_MAGICCLOSE|
+					WDIOF_KEEPALIVEPING,
+		.firmware_version =	1,
+		.identity =		"WDT500/501",
 	};
 
-	ident.options&=WDT_OPTION_MASK;	/* Mask down to the card we have */
+	/* Add options according to the card we have */
+	ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
+#ifdef CONFIG_WDT_501
+	ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
+	if (tachometer)
+		ident.options |= WDIOF_FANFAULT;
+#endif /* CONFIG_WDT_501 */
+
 	switch(cmd)
 	{
 		default:
@@ -338,23 +354,24 @@
 			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
 
 		case WDIOC_GETSTATUS:
-			return put_user(wdt_status(),(int *)arg);
+			wdt_get_status(&status);
+			return put_user(status,(int *)arg);
 		case WDIOC_GETBOOTSTATUS:
 			return put_user(0, (int *)arg);
 		case WDIOC_KEEPALIVE:
 			wdt_ping();
 			return 0;
 		case WDIOC_SETTIMEOUT:
-			if (get_user(new_margin, (int *)arg))
+			if (get_user(new_heartbeat, (int *)arg))
 				return -EFAULT;
-			/* Arbitrary, can't find the card's limits */
-			if ((new_margin < 0) || (new_margin > 60))
+
+			if (wdt_set_heartbeat(new_heartbeat))
 				return -EINVAL;
-			wd_margin = new_margin * 100;
+
 			wdt_ping();
 			/* Fall */
 		case WDIOC_GETTIMEOUT:
-			return put_user(wd_margin / 100, (int *)arg);
+			return put_user(heartbeat, (int *)arg);
 	}
 }
 
@@ -363,43 +380,26 @@
  *	@inode: inode of device
  *	@file: file handle to device
  *
- *	One of our two misc devices has been opened. The watchdog device is
- *	single open and on opening we load the counters. Counter zero is a
- *	100Hz cascade, into counter 1 which downcounts to reboot. When the
- *	counter triggers counter 2 downcounts the length of the reset pulse
- *	which set set to be as long as possible.
+ *	The watchdog device has been opened. The watchdog device is single
+ *	open and on opening we load the counters. Counter zero is a 100Hz
+ *	cascade, into counter 1 which downcounts to reboot. When the counter
+ *	triggers counter 2 downcounts the length of the reset pulse which
+ *	set set to be as long as possible.
  */
 
 static int wdt_open(struct inode *inode, struct file *file)
 {
-	switch(iminor(inode))
-	{
-		case WATCHDOG_MINOR:
-			if(test_and_set_bit(0, &wdt_is_open))
-				return -EBUSY;
-			/*
-			 *	Activate
-			 */
-
-			wdt_is_open=1;
-			inb_p(WDT_DC);		/* Disable */
-			wdt_ctr_mode(0,3);
-			wdt_ctr_mode(1,2);
-			wdt_ctr_mode(2,0);
-			wdt_ctr_load(0, 8948);		/* count at 100Hz */
-			wdt_ctr_load(1,wd_margin);	/* Timeout 120 seconds */
-			wdt_ctr_load(2,65535);
-			outb_p(0, WDT_DC);	/* Enable */
-			return 0;
-		case TEMP_MINOR:
-			return 0;
-		default:
-			return -ENODEV;
-	}
+	if(test_and_set_bit(0, &wdt_is_open))
+		return -EBUSY;
+	/*
+	 *	Activate
+	 */
+	wdt_start();
+	return 0;
 }
 
 /**
- *	wdt_close:
+ *	wdt_release:
  *	@inode: inode to board
  *	@file: file handle to board
  *
@@ -412,19 +412,72 @@
 
 static int wdt_release(struct inode *inode, struct file *file)
 {
-	if(iminor(inode)==WATCHDOG_MINOR)
-	{
-		if (expect_close == 42) {
-			inb_p(WDT_DC);		/* Disable counters */
-			wdt_ctr_load(2,0);	/* 0 length reset pulses now */
-		} else {
-			printk(KERN_CRIT "wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
-		}
+	if (expect_close == 42) {
+		wdt_stop();
 		clear_bit(0, &wdt_is_open);
-		expect_close = 0;
+	} else {
+		printk(KERN_CRIT "wdt: WDT device closed unexpectedly.  WDT will not stop!\n");
+		wdt_ping();
 	}
+	expect_close = 0;
+	return 0;
+}
+
+#ifdef CONFIG_WDT_501
+/**
+ *	wdt_temp_read:
+ *	@file: file handle to the watchdog board
+ *	@buf: buffer to write 1 byte into
+ *	@count: length of buffer
+ *	@ptr: offset (no seek allowed)
+ *
+ *	Temp_read reports the temperature in degrees Fahrenheit. The API is in
+ *	farenheit. It was designed by an imperial measurement luddite.
+ */
+
+static ssize_t wdt_temp_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+	int temperature;
+
+	/*  Can't seek (pread) on this device  */
+	if (ptr != &file->f_pos)
+		return -ESPIPE;
+
+	if (wdt_get_temperature(&temperature))
+		return -EFAULT;
+
+	if (copy_to_user (buf, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
+}
+
+/**
+ *	wdt_temp_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ *	The temperature device has been opened.
+ */
+
+static int wdt_temp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/**
+ *	wdt_temp_release:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The temperature device has been closed.
+ */
+
+static int wdt_temp_release(struct inode *inode, struct file *file)
+{
 	return 0;
 }
+#endif /* CONFIG_WDT_501 */
 
 /**
  *	notify_sys:
@@ -441,11 +494,9 @@
 static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
 	void *unused)
 {
-	if(code==SYS_DOWN || code==SYS_HALT)
-	{
+	if(code==SYS_DOWN || code==SYS_HALT) {
 		/* Turn the card off */
-		inb_p(WDT_DC);
-		wdt_ctr_load(2,0);
+		wdt_stop();
 	}
 	return NOTIFY_DONE;
 }
@@ -458,39 +509,41 @@
 static struct file_operations wdt_fops = {
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
-	.read		= wdt_read,
 	.write		= wdt_write,
 	.ioctl		= wdt_ioctl,
 	.open		= wdt_open,
 	.release	= wdt_release,
 };
 
-static struct miscdevice wdt_miscdev=
-{
+static struct miscdevice wdt_miscdev = {
 	.minor	= WATCHDOG_MINOR,
 	.name	= "watchdog",
 	.fops	= &wdt_fops,
 };
 
 #ifdef CONFIG_WDT_501
-static struct miscdevice temp_miscdev=
-{
+static struct file_operations wdt_temp_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= wdt_temp_read,
+	.open		= wdt_temp_open,
+	.release	= wdt_temp_release,
+};
+
+static struct miscdevice temp_miscdev = {
 	.minor	= TEMP_MINOR,
 	.name	= "temperature",
-	.fops	= &wdt_fops,
+	.fops	= &wdt_temp_fops,
 };
-#endif
+#endif /* CONFIG_WDT_501 */
 
 /*
  *	The WDT card needs to learn about soft shutdowns in order to
  *	turn the timebomb registers off.
  */
 
-static struct notifier_block wdt_notifier=
-{
+static struct notifier_block wdt_notifier = {
 	.notifier_call = wdt_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 /**
@@ -508,10 +561,10 @@
 	misc_deregister(&wdt_miscdev);
 #ifdef CONFIG_WDT_501
 	misc_deregister(&temp_miscdev);
-#endif
+#endif /* CONFIG_WDT_501 */
 	unregister_reboot_notifier(&wdt_notifier);
-	release_region(io,8);
 	free_irq(irq, NULL);
+	release_region(io,8);
 }
 
 /**
@@ -526,51 +579,67 @@
 {
 	int ret;
 
-	ret = misc_register(&wdt_miscdev);
-	if (ret) {
-		printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR);
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (wdt_set_heartbeat(heartbeat)) {
+		wdt_set_heartbeat(WD_TIMO);
+		printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<65536, using %d\n",
+			WD_TIMO);
+	}
+
+	if (!request_region(io, 8, "wdt501p")) {
+		printk(KERN_ERR "wdt: I/O address 0x%04x already in use\n", io);
+		ret = -EBUSY;
 		goto out;
 	}
+
 	ret = request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL);
 	if(ret) {
 		printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
-		goto outmisc;
-	}
-	if (!request_region(io, 8, "wdt501p")) {
-		printk(KERN_ERR "wdt: IO %X is not free.\n", io);
-		ret = -EBUSY;
-		goto outirq;
+		goto outreg;
 	}
+
 	ret = register_reboot_notifier(&wdt_notifier);
 	if(ret) {
-		printk(KERN_ERR "wdt: can't register reboot notifier (err=%d)\n", ret);
-		goto outreg;
+		printk(KERN_ERR "wdt: cannot register reboot notifier (err=%d)\n", ret);
+		goto outirq;
 	}
 
 #ifdef CONFIG_WDT_501
 	ret = misc_register(&temp_miscdev);
 	if (ret) {
-		printk(KERN_ERR "wdt: can't misc_register (temp) on minor=%d\n", TEMP_MINOR);
+		printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n",
+			TEMP_MINOR, ret);
 		goto outrbt;
 	}
-#endif
+#endif /* CONFIG_WDT_501 */
+
+	ret = misc_register(&wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto outmisc;
+	}
 
 	ret = 0;
-	printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io, irq);
+	printk(KERN_INFO "WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
+		io, irq, heartbeat, nowayout);
+#ifdef CONFIG_WDT_501
+	printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled"));
+#endif /* CONFIG_WDT_501 */
+
 out:
 	return ret;
 
+outmisc:
 #ifdef CONFIG_WDT_501
+	misc_deregister(&temp_miscdev);
+#endif /* CONFIG_WDT_501 */
 outrbt:
 	unregister_reboot_notifier(&wdt_notifier);
-#endif
-
-outreg:
-	release_region(io,8);
 outirq:
 	free_irq(irq, NULL);
-outmisc:
-	misc_deregister(&wdt_miscdev);
+outreg:
+	release_region(io,8);
 	goto out;
 }
 
diff -Nru a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
--- a/drivers/char/watchdog/wdt977.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/char/watchdog/wdt977.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 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 @@
 	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 @@
 	 */
 	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 @@
 			}
 		}
 
-		kick_wdog();
+		wdt977_keepalive();
 	}
 	return count;
 }
@@ -257,14 +312,19 @@
  */
 
 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 @@
 		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 @@
 	.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 -Nru a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
--- a/drivers/char/watchdog/wdt_pci.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/char/watchdog/wdt_pci.c	Sat Apr  3 19:38:44 2004
@@ -1,5 +1,5 @@
 /*
- *	Industrial Computer Source WDT500/501 driver for Linux 2.1.x
+ *	Industrial Computer Source PCI-WDT500/501 driver
  *
  *	(c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
  *				http://www.redhat.com
@@ -15,7 +15,7 @@
  *
  *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
- *	Release 0.09.
+ *	Release 0.10.
  *
  *	Fixes
  *		Dave Gregorich	:	Modularisation and minor bugs
@@ -46,6 +46,7 @@
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/fs.h>
 #include <linux/pci.h>
 
 #include <asm/io.h>
@@ -70,6 +71,9 @@
 #define PCI_DEVICE_ID_WDG_CSM 0x22c0
 #endif
 
+/* We can only use 1 card due to the /dev/watchdog restriction */
+static int dev_count;
+
 static struct semaphore open_sem;
 static spinlock_t wdtpci_lock;
 static char expect_close;
@@ -78,10 +82,12 @@
 static int irq;
 
 /* Default timeout */
-#define WD_TIMO (100*60)		/* 1 minute */
-#define WD_TIMO_MAX (WD_TIMO*60)	/* 1 hour(?) */
+#define WD_TIMO 60			/* Default heartbeat = 60 seconds */
 
-static int wd_margin = WD_TIMO;
+static int heartbeat = WD_TIMO;
+static int wd_heartbeat;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
 static int nowayout = 1;
@@ -92,6 +98,14 @@
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
+#ifdef CONFIG_WDT_501_PCI
+/* Support for the Fan Tachometer on the PCI-WDT501 */
+static int tachometer;
+
+module_param(tachometer, int, 0);
+MODULE_PARM_DESC(tachometer, "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
+#endif /* CONFIG_WDT_501_PCI */
+
 /*
  *	Programming support
  */
@@ -110,13 +124,105 @@
 	outb_p(val>>8, WDT_COUNT0+ctr);
 }
 
-/*
- *	Kernel methods.
+/**
+ *	wdtpci_start:
+ *
+ *	Start the watchdog driver.
  */
 
+static int wdtpci_start(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wdtpci_lock, flags);
+
+	/*
+	 * "pet" the watchdog, as Access says.
+	 * This resets the clock outputs.
+	 */
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdtpci_ctr_mode(2,0);		/* Program CTR2 for Mode 0: Pulse on Terminal Count */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+
+	inb_p(WDT_DC);			/* Disable watchdog */
+	outb_p(0, WDT_CLOCK);		/* 2.0833MHz clock */
+	inb_p(WDT_BUZZER);		/* disable */
+	inb_p(WDT_OPTONOTRST);		/* disable */
+	inb_p(WDT_OPTORST);		/* disable */
+	inb_p(WDT_PROGOUT);		/* disable */
+	wdtpci_ctr_mode(0,3);		/* Program CTR0 for Mode 3: Square Wave Generator */
+	wdtpci_ctr_mode(1,2);		/* Program CTR1 for Mode 2: Rate Generator */
+	wdtpci_ctr_mode(2,1);		/* Program CTR2 for Mode 1: Retriggerable One-Shot */
+	wdtpci_ctr_load(0,20833);	/* count at 100Hz */
+	wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */
+	/* DO NOT LOAD CTR2 on PCI card! -- JPN */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+
+	spin_unlock_irqrestore(&wdtpci_lock, flags);
+	return 0;
+}
+
+/**
+ *	wdtpci_stop:
+ *
+ *	Stop the watchdog driver.
+ */
+
+static int wdtpci_stop (void)
+{
+	unsigned long flags;
+
+	/* Turn the card off */
+	spin_lock_irqsave(&wdtpci_lock, flags);
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdtpci_ctr_load(2,0);		/* 0 length reset pulses now */
+	spin_unlock_irqrestore(&wdtpci_lock, flags);
+	return 0;
+}
+
+/**
+ *	wdtpci_ping:
+ *
+ *	Reload counter one with the watchdog heartbeat. We don't bother reloading
+ *	the cascade counter.
+ */
+
+static int wdtpci_ping(void)
+{
+	unsigned long flags;
+
+	/* Write a watchdog value */
+	spin_lock_irqsave(&wdtpci_lock, flags);
+	inb_p(WDT_DC);			/* Disable watchdog */
+	wdtpci_ctr_mode(1,2);		/* Re-Program CTR1 for Mode 2: Rate Generator */
+	wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */
+	outb_p(0, WDT_DC);		/* Enable watchdog */
+	spin_unlock_irqrestore(&wdtpci_lock, flags);
+	return 0;
+}
+
+/**
+ *	wdtpci_set_heartbeat:
+ *	@t:		the new heartbeat value that needs to be set.
+ *
+ *	Set a new heartbeat value for the watchdog device. If the heartbeat value is
+ *	incorrect we keep the old value and return -EINVAL. If successfull we
+ *	return 0.
+ */
+static int wdtpci_set_heartbeat(int t)
+{
+	/* Arbitrary, can't find the card's limits */
+	if ((t < 1) || (t > 65535))
+		return -EINVAL;
+
+	heartbeat = t;
+	wd_heartbeat = t * 100;
+	return 0;
+}
 
 /**
- *	wdtpci_status:
+ *	wdtpci_get_status:
+ *	@status:		the new status.
  *
  *	Extract the status information from a WDT watchdog device. There are
  *	several board variants so we have to know which bits are valid. Some
@@ -125,31 +231,46 @@
  *	we then map the bits onto the status ioctl flags.
  */
 
-static int wdtpci_status(void)
+static int wdtpci_get_status(int *status)
 {
-	/*
-	 *	Status register to bit flags
-	 */
+	unsigned char new_status=inb_p(WDT_SR);
 
-	int flag=0;
-	unsigned char status=inb_p(WDT_SR);
-	status|=FEATUREMAP1;
-	status&=~FEATUREMAP2;
+	*status=0;
+	if (new_status & WDC_SR_ISOI0)
+		*status |= WDIOF_EXTERN1;
+	if (new_status & WDC_SR_ISII1)
+		*status |= WDIOF_EXTERN2;
+#ifdef CONFIG_WDT_501_PCI
+	if (!(new_status & WDC_SR_TGOOD))
+		*status |= WDIOF_OVERHEAT;
+	if (!(new_status & WDC_SR_PSUOVER))
+		*status |= WDIOF_POWEROVER;
+	if (!(new_status & WDC_SR_PSUUNDR))
+		*status |= WDIOF_POWERUNDER;
+	if (tachometer) {
+		if (!(new_status & WDC_SR_FANGOOD))
+			*status |= WDIOF_FANFAULT;
+	}
+#endif /* CONFIG_WDT_501_PCI */
+	return 0;
+}
 
-	if(!(status&WDC_SR_TGOOD))
-		flag|=WDIOF_OVERHEAT;
-	if(!(status&WDC_SR_PSUOVER))
-		flag|=WDIOF_POWEROVER;
-	if(!(status&WDC_SR_PSUUNDR))
-		flag|=WDIOF_POWERUNDER;
-	if(!(status&WDC_SR_FANGOOD))
-		flag|=WDIOF_FANFAULT;
-	if(status&WDC_SR_ISOI0)
-		flag|=WDIOF_EXTERN1;
-	if(status&WDC_SR_ISII1)
-		flag|=WDIOF_EXTERN2;
-	return flag;
+#ifdef CONFIG_WDT_501_PCI
+/**
+ *	wdtpci_get_temperature:
+ *
+ *	Reports the temperature in degrees Fahrenheit. The API is in
+ *	farenheit. It was designed by an imperial measurement luddite.
+ */
+
+static int wdtpci_get_temperature(int *temperature)
+{
+	unsigned short c=inb_p(WDT_RT);
+
+	*temperature = (c * 11 / 15) + 7;
+	return 0;
 }
+#endif /* CONFIG_WDT_501_PCI */
 
 /**
  *	wdtpci_interrupt:
@@ -168,58 +289,38 @@
 	 *	Read the status register see what is up and
 	 *	then printk it.
 	 */
-
 	unsigned char status=inb_p(WDT_SR);
 
-	status|=FEATUREMAP1;
-	status&=~FEATUREMAP2;
-
-	printk(KERN_CRIT "WDT status %d\n", status);
+	printk(KERN_CRIT PFX "status %d\n", status);
 
-	if(!(status&WDC_SR_TGOOD))
-		printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
-	if(!(status&WDC_SR_PSUOVER))
-		printk(KERN_CRIT "PSU over voltage.\n");
-	if(!(status&WDC_SR_PSUUNDR))
-		printk(KERN_CRIT "PSU under voltage.\n");
-	if(!(status&WDC_SR_FANGOOD))
-		printk(KERN_CRIT "Possible fan fault.\n");
-	if(!(status&WDC_SR_WCCR))
+#ifdef CONFIG_WDT_501_PCI
+	if (!(status & WDC_SR_TGOOD))
+ 		printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",inb_p(WDT_RT));
+	if (!(status & WDC_SR_PSUOVER))
+ 		printk(KERN_CRIT PFX "PSU over voltage.\n");
+	if (!(status & WDC_SR_PSUUNDR))
+ 		printk(KERN_CRIT PFX "PSU under voltage.\n");
+	if (tachometer) {
+		if (!(status & WDC_SR_FANGOOD))
+			printk(KERN_CRIT PFX "Possible fan fault.\n");
+	}
+#endif /* CONFIG_WDT_501_PCI */
+	if (!(status&WDC_SR_WCCR))
 #ifdef SOFTWARE_REBOOT
 #ifdef ONLY_TESTING
-		printk(KERN_CRIT "Would Reboot.\n");
+		printk(KERN_CRIT PFX "Would Reboot.\n");
 #else
-		printk(KERN_CRIT "Initiating system reboot.\n");
+		printk(KERN_CRIT PFX "Initiating system reboot.\n");
 		machine_restart(NULL);
 #endif
 #else
-		printk(KERN_CRIT "Reset in 5ms.\n");
+		printk(KERN_CRIT PFX "Reset in 5ms.\n");
 #endif
 	return IRQ_HANDLED;
 }
 
 
 /**
- *	wdtpci_ping:
- *
- *	Reload counter one with the watchdog timeout. We don't bother reloading
- *	the cascade counter.
- */
-
-static void wdtpci_ping(void)
-{
-	unsigned long flags;
-
-	/* Write a watchdog value */
-	spin_lock_irqsave(&wdtpci_lock, flags);
-	inb_p(WDT_DC);
-	wdtpci_ctr_mode(1,2);
-	wdtpci_ctr_load(1,wd_margin);		/* Timeout */
-	outb_p(0, WDT_DC);
-	spin_unlock_irqrestore(&wdtpci_lock, flags);
-}
-
-/**
  *	wdtpci_write:
  *	@file: file handle to the watchdog
  *	@buf: buffer to write (unused as data does not matter here
@@ -257,40 +358,6 @@
 }
 
 /**
- *	wdtpci_read:
- *	@file: file handle to the watchdog board
- *	@buf: buffer to write 1 byte into
- *	@count: length of buffer
- *	@ptr: offset (no seek allowed)
- *
- *	Read reports the temperature in degrees Fahrenheit. The API is in
- *	fahrenheit. It was designed by an imperial measurement luddite.
- */
-
-static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr)
-{
-	unsigned short c=inb_p(WDT_RT);
-	unsigned char cp;
-
-	/*  Can't seek (pread) on this device  */
-	if (ptr != &file->f_pos)
-		return -ESPIPE;
-
-	switch(iminor(file->f_dentry->d_inode))
-	{
-		case TEMP_MINOR:
-			c*=11;
-			c/=15;
-			cp=c+7;
-			if(copy_to_user(buf,&cp,1))
-				return -EFAULT;
-			return 1;
-		default:
-			return -EINVAL;
-	}
-}
-
-/**
  *	wdtpci_ioctl:
  *	@inode: inode of the device
  *	@file: file handle to the device
@@ -305,17 +372,25 @@
 static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	unsigned long arg)
 {
-	int new_margin;
+	int new_heartbeat;
+	int status;
+
 	static struct watchdog_info ident = {
-		.options	= WDIOF_OVERHEAT  | WDIOF_POWERUNDER |
-				  WDIOF_POWEROVER | WDIOF_EXTERN1 |
-				  WDIOF_EXTERN2   | WDIOF_FANFAULT |
-				  WDIOF_SETTIMEOUT|WDIOF_MAGICCLOSE,
-		.firmware_version = 1,
-		.identity	  = "WDT500/501PCI",
+		.options =		WDIOF_SETTIMEOUT|
+					WDIOF_MAGICCLOSE|
+					WDIOF_KEEPALIVEPING,
+		.firmware_version =	1,
+		.identity =		"PCI-WDT500/501",
 	};
 
-	ident.options&=WDT_OPTION_MASK;	/* Mask down to the card we have */
+	/* Add options according to the card we have */
+	ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
+#ifdef CONFIG_WDT_501_PCI
+	ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
+	if (tachometer)
+		ident.options |= WDIOF_FANFAULT;
+#endif /* CONFIG_WDT_501_PCI */
+
 	switch(cmd)
 	{
 		default:
@@ -324,24 +399,24 @@
 			return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
 
 		case WDIOC_GETSTATUS:
-			return put_user(wdtpci_status(),(int *)arg);
+			wdtpci_get_status(&status);
+			return put_user(status,(int *)arg);
 		case WDIOC_GETBOOTSTATUS:
 			return put_user(0, (int *)arg);
 		case WDIOC_KEEPALIVE:
 			wdtpci_ping();
 			return 0;
 		case WDIOC_SETTIMEOUT:
-			if (get_user(new_margin, (int *)arg))
+			if (get_user(new_heartbeat, (int *)arg))
 				return -EFAULT;
-			/* Arbitrary, can't find the card's limits */
-			new_margin *= 100;
-			if ((new_margin < 0) || (new_margin > WD_TIMO_MAX))
+
+			if (wdtpci_set_heartbeat(new_heartbeat))
 				return -EINVAL;
-			wd_margin = new_margin;
+
 			wdtpci_ping();
 			/* Fall */
 		case WDIOC_GETTIMEOUT:
-			return put_user(wd_margin / 100, (int *)arg);
+			return put_user(heartbeat, (int *)arg);
 	}
 }
 
@@ -350,66 +425,30 @@
  *	@inode: inode of device
  *	@file: file handle to device
  *
- *	One of our two misc devices has been opened. The watchdog device is
- *	single open and on opening we load the counters. Counter zero is a
- *	100Hz cascade, into counter 1 which downcounts to reboot. When the
- *	counter triggers counter 2 downcounts the length of the reset pulse
- *	which set set to be as long as possible.
+ *	The watchdog device has been opened. The watchdog device is single
+ *	open and on opening we load the counters. Counter zero is a 100Hz
+ *	cascade, into counter 1 which downcounts to reboot. When the counter
+ *	triggers counter 2 downcounts the length of the reset pulse which
+ *	set set to be as long as possible.
  */
 
 static int wdtpci_open(struct inode *inode, struct file *file)
 {
-	unsigned long flags;
+	if (down_trylock(&open_sem))
+		return -EBUSY;
 
-	switch(iminor(inode))
-	{
-		case WATCHDOG_MINOR:
-			if (down_trylock(&open_sem))
-				return -EBUSY;
-
-			if (nowayout) {
-				__module_get(THIS_MODULE);
-			}
-			/*
-			 *	Activate
-			 */
-			spin_lock_irqsave(&wdtpci_lock, flags);
-
-			inb_p(WDT_DC);		/* Disable */
-
-			/*
-			 * "pet" the watchdog, as Access says.
-			 * This resets the clock outputs.
-			 */
-
-			wdtpci_ctr_mode(2,0);
-			outb_p(0, WDT_DC);
-
-			inb_p(WDT_DC);
-
-			outb_p(0, WDT_CLOCK);	/* 2.0833MHz clock */
-			inb_p(WDT_BUZZER);	/* disable */
-			inb_p(WDT_OPTONOTRST);	/* disable */
-			inb_p(WDT_OPTORST);	/* disable */
-			inb_p(WDT_PROGOUT);	/* disable */
-			wdtpci_ctr_mode(0,3);
-			wdtpci_ctr_mode(1,2);
-			wdtpci_ctr_mode(2,1);
-			wdtpci_ctr_load(0,20833);	/* count at 100Hz */
-			wdtpci_ctr_load(1,wd_margin);/* Timeout 60 seconds */
-			/* DO NOT LOAD CTR2 on PCI card! -- JPN */
-			outb_p(0, WDT_DC);	/* Enable */
-			spin_unlock_irqrestore(&wdtpci_lock, flags);
-			return 0;
-		case TEMP_MINOR:
-			return 0;
-		default:
-			return -ENODEV;
+	if (nowayout) {
+		__module_get(THIS_MODULE);
 	}
+	/*
+	 *	Activate
+	 */
+	wdtpci_start();
+	return 0;
 }
 
 /**
- *	wdtpci_close:
+ *	wdtpci_release:
  *	@inode: inode to board
  *	@file: file handle to board
  *
@@ -422,24 +461,73 @@
 
 static int wdtpci_release(struct inode *inode, struct file *file)
 {
-
-	if (iminor(inode)==WATCHDOG_MINOR) {
-		unsigned long flags;
-		if (expect_close == 42) {
-			spin_lock_irqsave(&wdtpci_lock, flags);
-			inb_p(WDT_DC);		/* Disable counters */
-			wdtpci_ctr_load(2,0);	/* 0 length reset pulses now */
-			spin_unlock_irqrestore(&wdtpci_lock, flags);
-		} else {
-			printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
-			wdtpci_ping();
-		}
-		expect_close = 0;
-		up(&open_sem);
+	if (expect_close == 42) {
+		wdtpci_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
+		wdtpci_ping();
 	}
+	expect_close = 0;
+	up(&open_sem);
 	return 0;
 }
 
+#ifdef CONFIG_WDT_501_PCI
+/**
+ *	wdtpci_temp_read:
+ *	@file: file handle to the watchdog board
+ *	@buf: buffer to write 1 byte into
+ *	@count: length of buffer
+ *	@ptr: offset (no seek allowed)
+ *
+ *	Read reports the temperature in degrees Fahrenheit. The API is in
+ *	fahrenheit. It was designed by an imperial measurement luddite.
+ */
+
+static ssize_t wdtpci_temp_read(struct file *file, char *buf, size_t count, loff_t *ptr)
+{
+	int temperature;
+
+	/*  Can't seek (pread) on this device  */
+	if (ptr != &file->f_pos)
+		return -ESPIPE;
+
+	if (wdtpci_get_temperature(&temperature))
+		return -EFAULT;
+
+	if (copy_to_user (buf, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
+}
+
+/**
+ *	wdtpci_temp_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ *	The temperature device has been opened.
+ */
+
+static int wdtpci_temp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/**
+ *	wdtpci_temp_release:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The temperature device has been closed.
+ */
+
+static int wdtpci_temp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+#endif /* CONFIG_WDT_501_PCI */
+
 /**
  *	notify_sys:
  *	@this: our notifier block
@@ -455,14 +543,9 @@
 static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
 	void *unused)
 {
-	unsigned long flags;
-
 	if (code==SYS_DOWN || code==SYS_HALT) {
 		/* Turn the card off */
-		spin_lock_irqsave(&wdtpci_lock, flags);
-		inb_p(WDT_DC);
-		wdtpci_ctr_load(2,0);
-		spin_unlock_irqrestore(&wdtpci_lock, flags);
+		wdtpci_stop();
 	}
 	return NOTIFY_DONE;
 }
@@ -475,7 +558,6 @@
 static struct file_operations wdtpci_fops = {
 	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
-	.read		= wdtpci_read,
 	.write		= wdtpci_write,
 	.ioctl		= wdtpci_ioctl,
 	.open		= wdtpci_open,
@@ -489,12 +571,20 @@
 };
 
 #ifdef CONFIG_WDT_501_PCI
+static struct file_operations wdtpci_temp_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= wdtpci_temp_read,
+	.open		= wdtpci_temp_open,
+	.release	= wdtpci_temp_release,
+};
+
 static struct miscdevice temp_miscdev = {
 	.minor	= TEMP_MINOR,
 	.name	= "temperature",
-	.fops	= &wdtpci_fops,
+	.fops	= &wdtpci_temp_fops,
 };
-#endif
+#endif /* CONFIG_WDT_501_PCI */
 
 /*
  *	The WDT card needs to learn about soft shutdowns in order to
@@ -509,71 +599,96 @@
 static int __devinit wdtpci_init_one (struct pci_dev *dev,
 				   const struct pci_device_id *ent)
 {
-	static int dev_count = 0;
 	int ret = -EIO;
 
 	dev_count++;
 	if (dev_count > 1) {
-		printk (KERN_ERR PFX
-			"this driver only supports 1 device\n");
+		printk (KERN_ERR PFX "this driver only supports 1 device\n");
 		return -ENODEV;
 	}
 
-	if (pci_enable_device (dev))
-		goto out;
+	if (pci_enable_device (dev)) {
+		printk (KERN_ERR PFX "Not possible to enable PCI Device\n");
+		return -ENODEV;
+	}
+
+	if (pci_resource_start (dev, 2) == 0x0000) {
+		printk (KERN_ERR PFX "No I/O-Address for card detected\n");
+		ret = -ENODEV;
+		goto out_pci;
+	}
 
 	sema_init(&open_sem, 1);
 	spin_lock_init(&wdtpci_lock);
 
 	irq = dev->irq;
 	io = pci_resource_start (dev, 2);
-	printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X "
-		"(Interrupt %d)\n", io, irq);
 
-	if (request_region (io, 16, "wdt-pci") == NULL) {
-		printk (KERN_ERR PFX "I/O %d is not free.\n", io);
-		goto out;
+	if (request_region (io, 16, "wdt_pci") == NULL) {
+		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", io);
+		goto out_pci;
 	}
 
 	if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ,
-			 "wdt-pci", &wdtpci_miscdev)) {
-		printk (KERN_ERR PFX "IRQ %d is not free.\n", irq);
+			 "wdt_pci", &wdtpci_miscdev)) {
+		printk (KERN_ERR PFX "IRQ %d is not free\n", irq);
 		goto out_reg;
 	}
 
-	ret = misc_register (&wdtpci_miscdev);
-	if (ret) {
-		printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR);
-		goto out_irq;
+	printk ("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%04x (Interrupt %d)\n",
+		io, irq);
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (wdtpci_set_heartbeat(heartbeat)) {
+		wdtpci_set_heartbeat(WD_TIMO);
+		printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
+			WD_TIMO);
 	}
 
 	ret = register_reboot_notifier (&wdtpci_notifier);
 	if (ret) {
-		printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR);
-		goto out_misc;
+		printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+		goto out_irq;
 	}
+
 #ifdef CONFIG_WDT_501_PCI
 	ret = misc_register (&temp_miscdev);
 	if (ret) {
-		printk (KERN_ERR PFX "can't misc_register (temp) on minor=%d\n", TEMP_MINOR);
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			TEMP_MINOR, ret);
 		goto out_rbt;
 	}
-#endif
+#endif /* CONFIG_WDT_501_PCI */
+
+	ret = misc_register (&wdtpci_miscdev);
+	if (ret) {
+		printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto out_misc;
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
+#ifdef CONFIG_WDT_501_PCI
+	printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled"));
+#endif /* CONFIG_WDT_501_PCI */
 
 	ret = 0;
 out:
 	return ret;
 
+out_misc:
 #ifdef CONFIG_WDT_501_PCI
+	misc_deregister(&temp_miscdev);
+#endif /* CONFIG_WDT_501_PCI */
 out_rbt:
 	unregister_reboot_notifier(&wdtpci_notifier);
-#endif
-out_misc:
-	misc_deregister(&wdtpci_miscdev);
 out_irq:
 	free_irq(irq, &wdtpci_miscdev);
 out_reg:
 	release_region (io, 16);
+out_pci:
+	pci_disable_device(dev);
 	goto out;
 }
 
@@ -582,13 +697,15 @@
 {
 	/* here we assume only one device will ever have
 	 * been picked up and registered by probe function */
-	unregister_reboot_notifier(&wdtpci_notifier);
+	misc_deregister(&wdtpci_miscdev);
 #ifdef CONFIG_WDT_501_PCI
 	misc_deregister(&temp_miscdev);
-#endif
-	misc_deregister(&wdtpci_miscdev);
+#endif /* CONFIG_WDT_501_PCI */
+	unregister_reboot_notifier(&wdtpci_notifier);
 	free_irq(irq, &wdtpci_miscdev);
 	release_region(io, 16);
+	pci_disable_device(pdev);
+	dev_count--;
 }
 
 
@@ -605,7 +722,7 @@
 
 
 static struct pci_driver wdtpci_driver = {
-	.name		= "wdt-pci",
+	.name		= "wdt_pci",
 	.id_table	= wdtpci_pci_tbl,
 	.probe		= wdtpci_init_one,
 	.remove		= __devexit_p(wdtpci_remove_one),
@@ -619,7 +736,7 @@
  *	If your watchdog is set to continue ticking on close and you unload
  *	it, well it keeps ticking. We won't get the interrupt but the board
  *	will not touch PC memory so all is fine. You just have to load a new
- *	module in 60 seconds or reboot.
+ *	module in xx seconds or reboot.
  */
 
 static void __exit wdtpci_cleanup(void)
@@ -638,12 +755,7 @@
 
 static int __init wdtpci_init(void)
 {
-	int rc = pci_register_driver (&wdtpci_driver);
-
-	if (rc < 1)
-		return -ENODEV;
-
-	return 0;
+	return pci_register_driver (&wdtpci_driver);
 }
 
 
@@ -651,7 +763,7 @@
 module_exit(wdtpci_cleanup);
 
 MODULE_AUTHOR("JP Nollmann, Alan Cox");
-MODULE_DESCRIPTION("Driver for the ICS PCI watchdog cards");
+MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff -Nru a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
--- a/drivers/eisa/eisa-bus.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/eisa/eisa-bus.c	Sat Apr  3 19:38:42 2004
@@ -187,6 +187,7 @@
 	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 -Nru a/drivers/fc4/soc.h b/drivers/fc4/soc.h
--- a/drivers/fc4/soc.h	Sat Apr  3 19:38:40 2004
+++ b/drivers/fc4/soc.h	Sat Apr  3 19:38:40 2004
@@ -114,18 +114,22 @@
 static inline void xram_copy_from (void *p, xram_p x, int len)
 {
 	for (len >>= 2; len > 0; len--, x += sizeof(u32)) {
-		u32 val;
+		u32 val, *p32 = p;
 
 		val = ((sbus_readw(x + 0x00UL) << 16) |
 		       (sbus_readw(x + 0x02UL)));
-		*((u32 *)p)++ = val;
+		*p32++ = val;
+		p = p32;
 	}
 }
 
 static inline void xram_copy_to (xram_p x, void *p, int len)
 {
 	for (len >>= 2; len > 0; len--, x += sizeof(u32)) {
-		u32 tmp = *((u32 *)p)++;
+		u32 tmp, *p32 = p;
+
+		tmp = *p32++;
+		p = p32;
 		sbus_writew(tmp >> 16, x + 0x00UL);
 		sbus_writew(tmp, x + 0x02UL);
 	}
diff -Nru a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/firmware/Kconfig	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,19 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+menu "Firmware Drivers"
+
+config EDD
+	tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  Say Y or M here if you want to enable BIOS Enhanced Disk Drive
+	  Services real mode BIOS calls to determine which disk
+	  BIOS tries boot from.  This information is then exported via driverfs.
+
+	  This option is experimental, but believed to be safe,
+	  and most disk controller BIOS vendors do not yet implement this feature.
+
+endmenu
diff -Nru a/drivers/firmware/Makefile b/drivers/firmware/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/firmware/Makefile	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,4 @@
+#
+# Makefile for the linux kernel.
+#
+obj-$(CONFIG_EDD)             	+= edd.o
diff -Nru a/drivers/firmware/edd.c b/drivers/firmware/edd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/firmware/edd.c	Sat Apr  3 19:38:42 2004
@@ -0,0 +1,837 @@
+/*
+ * linux/arch/i386/kernel/edd.c
+ *  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
+ *   projects 1572D, 1484D, 1386D, 1226DT
+ *
+ * This code takes information provided by BIOS EDD calls
+ * fn41 - Check Extensions Present and
+ * fn48 - Get Device Parametes with EDD extensions
+ * made in setup.S, copied to safe structures in setup.c,
+ * and presents it in sysfs.
+ *
+ * Please see http://domsch.com/linux/edd30/results.html for
+ * the list of BIOSs which have been reported to implement EDD.
+ * If you don't see yours listed, please send a report as described there.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * 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.
+ *
+ */
+
+/*
+ * Known issues:
+ * - refcounting of struct device objects could be improved.
+ *
+ * TODO:
+ * - Add IDE and USB disk device support
+ * - move edd.[ch] to better locations if/when one is decided
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/limits.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/blkdev.h>
+#include <linux/edd.h>
+/* FIXME - this really belongs in include/scsi/scsi.h */
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+
+MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
+MODULE_DESCRIPTION("sysfs interface to BIOS EDD information");
+MODULE_LICENSE("GPL");
+
+#define EDD_VERSION "0.13 2004-Mar-09"
+#define EDD_DEVICE_NAME_SIZE 16
+#define REPORT_URL "http://linux.dell.com/edd/results.html"
+
+#define left (PAGE_SIZE - (p - buf) - 1)
+
+struct edd_device {
+	struct edd_info *info;
+	struct kobject kobj;
+};
+
+struct edd_attribute {
+	struct attribute attr;
+	ssize_t(*show) (struct edd_device * edev, char *buf);
+	int (*test) (struct edd_device * edev);
+};
+
+/* forward declarations */
+static int edd_dev_is_type(struct edd_device *edev, const char *type);
+static struct pci_dev *edd_get_pci_dev(struct edd_device *edev);
+
+static struct edd_device *edd_devices[EDDMAXNR];
+
+#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
+struct edd_attribute edd_attr_##_name = { 	\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.show	= _show,				\
+	.test	= _test,				\
+};
+
+static inline struct edd_info *
+edd_dev_get_info(struct edd_device *edev)
+{
+	return edev->info;
+}
+
+static inline void
+edd_dev_set_info(struct edd_device *edev, struct edd_info *info)
+{
+	edev->info = info;
+}
+
+#define to_edd_attr(_attr) container_of(_attr,struct edd_attribute,attr)
+#define to_edd_device(obj) container_of(obj,struct edd_device,kobj)
+
+static ssize_t
+edd_attr_show(struct kobject * kobj, struct attribute *attr, char *buf)
+{
+	struct edd_device *dev = to_edd_device(kobj);
+	struct edd_attribute *edd_attr = to_edd_attr(attr);
+	ssize_t ret = 0;
+
+	if (edd_attr->show)
+		ret = edd_attr->show(dev, buf);
+	return ret;
+}
+
+static struct sysfs_ops edd_attr_ops = {
+	.show = edd_attr_show,
+};
+
+static ssize_t
+edd_show_host_bus(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	int i;
+
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (isprint(info->params.host_bus_type[i])) {
+			p += scnprintf(p, left, "%c", info->params.host_bus_type[i]);
+		} else {
+			p += scnprintf(p, left, " ");
+		}
+	}
+
+	if (!strncmp(info->params.host_bus_type, "ISA", 3)) {
+		p += scnprintf(p, left, "\tbase_address: %x\n",
+			     info->params.interface_path.isa.base_address);
+	} else if (!strncmp(info->params.host_bus_type, "PCIX", 4) ||
+		   !strncmp(info->params.host_bus_type, "PCI", 3)) {
+		p += scnprintf(p, left,
+			     "\t%02x:%02x.%d  channel: %u\n",
+			     info->params.interface_path.pci.bus,
+			     info->params.interface_path.pci.slot,
+			     info->params.interface_path.pci.function,
+			     info->params.interface_path.pci.channel);
+	} else if (!strncmp(info->params.host_bus_type, "IBND", 4) ||
+		   !strncmp(info->params.host_bus_type, "XPRS", 4) ||
+		   !strncmp(info->params.host_bus_type, "HTPT", 4)) {
+		p += scnprintf(p, left,
+			     "\tTBD: %llx\n",
+			     info->params.interface_path.ibnd.reserved);
+
+	} else {
+		p += scnprintf(p, left, "\tunknown: %llx\n",
+			     info->params.interface_path.unknown.reserved);
+	}
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_interface(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	int i;
+
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	for (i = 0; i < 8; i++) {
+		if (isprint(info->params.interface_type[i])) {
+			p += scnprintf(p, left, "%c", info->params.interface_type[i]);
+		} else {
+			p += scnprintf(p, left, " ");
+		}
+	}
+	if (!strncmp(info->params.interface_type, "ATAPI", 5)) {
+		p += scnprintf(p, left, "\tdevice: %u  lun: %u\n",
+			     info->params.device_path.atapi.device,
+			     info->params.device_path.atapi.lun);
+	} else if (!strncmp(info->params.interface_type, "ATA", 3)) {
+		p += scnprintf(p, left, "\tdevice: %u\n",
+			     info->params.device_path.ata.device);
+	} else if (!strncmp(info->params.interface_type, "SCSI", 4)) {
+		p += scnprintf(p, left, "\tid: %u  lun: %llu\n",
+			     info->params.device_path.scsi.id,
+			     info->params.device_path.scsi.lun);
+	} else if (!strncmp(info->params.interface_type, "USB", 3)) {
+		p += scnprintf(p, left, "\tserial_number: %llx\n",
+			     info->params.device_path.usb.serial_number);
+	} else if (!strncmp(info->params.interface_type, "1394", 4)) {
+		p += scnprintf(p, left, "\teui: %llx\n",
+			     info->params.device_path.i1394.eui);
+	} else if (!strncmp(info->params.interface_type, "FIBRE", 5)) {
+		p += scnprintf(p, left, "\twwid: %llx lun: %llx\n",
+			     info->params.device_path.fibre.wwid,
+			     info->params.device_path.fibre.lun);
+	} else if (!strncmp(info->params.interface_type, "I2O", 3)) {
+		p += scnprintf(p, left, "\tidentity_tag: %llx\n",
+			     info->params.device_path.i2o.identity_tag);
+	} else if (!strncmp(info->params.interface_type, "RAID", 4)) {
+		p += scnprintf(p, left, "\tidentity_tag: %x\n",
+			     info->params.device_path.raid.array_number);
+	} else if (!strncmp(info->params.interface_type, "SATA", 4)) {
+		p += scnprintf(p, left, "\tdevice: %u\n",
+			     info->params.device_path.sata.device);
+	} else {
+		p += scnprintf(p, left, "\tunknown: %llx %llx\n",
+			     info->params.device_path.unknown.reserved1,
+			     info->params.device_path.unknown.reserved2);
+	}
+
+	return (p - buf);
+}
+
+/**
+ * edd_show_raw_data() - copies raw data to buffer for userspace to parse
+ *
+ * Returns: number of bytes written, or -EINVAL on failure
+ */
+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->params);
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE))
+		len = info->params.length;
+
+	/* In case of buggy BIOSs */
+	if (len > (sizeof(info->params)))
+		len = sizeof(info->params);
+
+	memcpy(buf, &info->params, len);
+	return len;
+}
+
+static ssize_t
+edd_show_version(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 += scnprintf(p, left, "0x%02x\n", info->version);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_disk80_sig(struct edd_device *edev, char *buf)
+{
+	char *p = buf;
+	p += scnprintf(p, left, "0x%08x\n", edd_disk80_sig);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_extensions(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	if (info->interface_support & EDD_EXT_FIXED_DISK_ACCESS) {
+		p += scnprintf(p, left, "Fixed disk access\n");
+	}
+	if (info->interface_support & EDD_EXT_DEVICE_LOCKING_AND_EJECTING) {
+		p += scnprintf(p, left, "Device locking and ejecting\n");
+	}
+	if (info->interface_support & EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT) {
+		p += scnprintf(p, left, "Enhanced Disk Drive support\n");
+	}
+	if (info->interface_support & EDD_EXT_64BIT_EXTENSIONS) {
+		p += scnprintf(p, left, "64-bit extensions\n");
+	}
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_info_flags(struct edd_device *edev, char *buf)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	if (info->params.info_flags & EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT)
+		p += scnprintf(p, left, "DMA boundary error transparent\n");
+	if (info->params.info_flags & EDD_INFO_GEOMETRY_VALID)
+		p += scnprintf(p, left, "geometry valid\n");
+	if (info->params.info_flags & EDD_INFO_REMOVABLE)
+		p += scnprintf(p, left, "removable\n");
+	if (info->params.info_flags & EDD_INFO_WRITE_VERIFY)
+		p += scnprintf(p, left, "write verify\n");
+	if (info->params.info_flags & EDD_INFO_MEDIA_CHANGE_NOTIFICATION)
+		p += scnprintf(p, left, "media change notification\n");
+	if (info->params.info_flags & EDD_INFO_LOCKABLE)
+		p += scnprintf(p, left, "lockable\n");
+	if (info->params.info_flags & EDD_INFO_NO_MEDIA_PRESENT)
+		p += scnprintf(p, left, "no media present\n");
+	if (info->params.info_flags & EDD_INFO_USE_INT13_FN50)
+		p += scnprintf(p, left, "use int13 fn50\n");
+	return (p - buf);
+}
+
+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);
+	char *p = buf;
+	if (!edev || !info || !buf) {
+		return -EINVAL;
+	}
+
+	p += scnprintf(p, left, "0x%x\n", info->params.num_default_cylinders);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_default_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 += scnprintf(p, left, "0x%x\n", info->params.num_default_heads);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_default_sectors_per_track(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 += scnprintf(p, left, "0x%x\n", info->params.sectors_per_track);
+	return (p - buf);
+}
+
+static ssize_t
+edd_show_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 += scnprintf(p, left, "0x%llx\n", info->params.number_of_sectors);
+	return (p - buf);
+}
+
+
+/*
+ * Some device instances may not have all the above attributes,
+ * or the attribute values may be meaningless (i.e. if
+ * the device is < EDD 3.0, it won't have host_bus and interface
+ * information), so don't bother making files for them.  Likewise
+ * if the default_{cylinders,heads,sectors_per_track} values
+ * are zero, the BIOS doesn't provide sane values, don't bother
+ * creating files for them either.
+ */
+
+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);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->params.num_default_cylinders > 0;
+}
+
+static int
+edd_has_default_heads(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->params.num_default_heads > 0;
+}
+
+static int
+edd_has_default_sectors_per_track(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return -EINVAL;
+	return info->params.sectors_per_track > 0;
+}
+
+static int
+edd_has_edd30(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	int i, nonzero_path = 0;
+	char c;
+
+	if (!edev || !info)
+		return 0;
+
+	if (!(info->params.key == 0xBEDD || info->params.key == 0xDDBE)) {
+		return 0;
+	}
+
+	for (i = 30; i <= 73; i++) {
+		c = *(((uint8_t *) info) + i + 4);
+		if (c) {
+			nonzero_path++;
+			break;
+		}
+	}
+	if (!nonzero_path) {
+		return 0;
+	}
+
+	return 1;
+}
+
+static int
+edd_has_disk80_sig(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+	if (!edev || !info)
+		return 0;
+	return info->device == 0x80;
+}
+
+static EDD_DEVICE_ATTR(raw_data, 0444, edd_show_raw_data, NULL);
+static EDD_DEVICE_ATTR(version, 0444, edd_show_version, NULL);
+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,
+		       edd_has_default_heads);
+static EDD_DEVICE_ATTR(default_sectors_per_track, 0444,
+		       edd_show_default_sectors_per_track,
+		       edd_has_default_sectors_per_track);
+static EDD_DEVICE_ATTR(interface, 0444, edd_show_interface, edd_has_edd30);
+static EDD_DEVICE_ATTR(host_bus, 0444, edd_show_host_bus, edd_has_edd30);
+static EDD_DEVICE_ATTR(mbr_signature, 0444, edd_show_disk80_sig, edd_has_disk80_sig);
+
+
+/* These are default attributes that are added for every edd
+ * device discovered.
+ */
+static struct attribute * def_attrs[] = {
+	&edd_attr_raw_data.attr,
+	&edd_attr_version.attr,
+	&edd_attr_extensions.attr,
+	&edd_attr_info_flags.attr,
+	&edd_attr_sectors.attr,
+	NULL,
+};
+
+/* 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,
+	&edd_attr_interface,
+	&edd_attr_host_bus,
+	&edd_attr_mbr_signature,
+	NULL,
+};
+
+/**
+ *	edd_release - free edd structure
+ *	@kobj:	kobject of edd structure
+ *
+ *	This is called when the refcount of the edd structure
+ *	reaches 0. This should happen right after we unregister,
+ *	but just in case, we use the release callback anyway.
+ */
+
+static void edd_release(struct kobject * kobj)
+{
+	struct edd_device * dev = to_edd_device(kobj);
+	kfree(dev);
+}
+
+static struct kobj_type ktype_edd = {
+	.release	= edd_release,
+	.sysfs_ops	= &edd_attr_ops,
+	.default_attrs	= def_attrs,
+};
+
+static decl_subsys(edd,&ktype_edd,NULL);
+
+
+/**
+ * edd_dev_is_type() - is this EDD device a 'type' device?
+ * @edev
+ * @type - a host bus or interface identifier string per the EDD spec
+ *
+ * Returns 1 (TRUE) if it is a 'type' device, 0 otherwise.
+ */
+static int
+edd_dev_is_type(struct edd_device *edev, const char *type)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+
+	if (edev && type && info) {
+		if (!strncmp(info->params.host_bus_type, type, strlen(type)) ||
+		    !strncmp(info->params.interface_type, type, strlen(type)))
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * edd_get_pci_dev() - finds pci_dev that matches edev
+ * @edev - edd_device
+ *
+ * Returns pci_dev if found, or NULL
+ */
+static struct pci_dev *
+edd_get_pci_dev(struct edd_device *edev)
+{
+	struct edd_info *info = edd_dev_get_info(edev);
+
+	if (edd_dev_is_type(edev, "PCI")) {
+		return pci_find_slot(info->params.interface_path.pci.bus,
+				     PCI_DEVFN(info->params.interface_path.pci.slot,
+					       info->params.interface_path.pci.
+					       function));
+	}
+	return NULL;
+}
+
+static int
+edd_create_symlink_to_pcidev(struct edd_device *edev)
+{
+
+	struct pci_dev *pci_dev = edd_get_pci_dev(edev);
+	if (!pci_dev)
+		return 1;
+	return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
+}
+
+/*
+ * FIXME - as of 15-Jan-2003, there are some non-"scsi_device"s on the
+ * scsi_bus list.  The following functions could possibly mis-access
+ * memory in that case.  This is actually a problem with the SCSI
+ * layer, which is being addressed there.  Until then, don't use the
+ * SCSI functions.
+ */
+
+#undef CONFIG_SCSI
+#undef CONFIG_SCSI_MODULE
+#if defined(CONFIG_SCSI) || defined(CONFIG_SCSI_MODULE)
+
+struct edd_match_data {
+	struct edd_device	* edev;
+	struct scsi_device	* sd;
+};
+
+/**
+ * edd_match_scsidev()
+ * @edev - EDD device is a known SCSI device
+ * @sd - scsi_device with host who's parent is a PCI controller
+ *
+ * returns 1 if a match is found, 0 if not.
+ */
+static int edd_match_scsidev(struct device * dev, void * d)
+{
+	struct edd_match_data * data = (struct edd_match_data *)d;
+	struct edd_info *info = edd_dev_get_info(data->edev);
+	struct scsi_device * sd = to_scsi_device(dev);
+
+	if (info) {
+		if ((sd->channel == info->params.interface_path.pci.channel) &&
+		    (sd->id == info->params.device_path.scsi.id) &&
+		    (sd->lun == info->params.device_path.scsi.lun)) {
+			data->sd = sd;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/**
+ * edd_find_matching_device()
+ * @edev - edd_device to match
+ *
+ * Search the SCSI devices for a drive that matches the EDD
+ * device descriptor we have. If we find a match, return it,
+ * otherwise, return NULL.
+ */
+
+static struct scsi_device *
+edd_find_matching_scsi_device(struct edd_device *edev)
+{
+	struct edd_match_data data;
+	struct bus_type * scsi_bus = find_bus("scsi");
+
+	if (!scsi_bus) {
+		return NULL;
+	}
+
+	data.edev = edev;
+
+	if (edd_dev_is_type(edev, "SCSI")) {
+		if (bus_for_each_dev(scsi_bus,NULL,&data,edd_match_scsidev))
+			return data.sd;
+	}
+	return NULL;
+}
+
+static int
+edd_create_symlink_to_scsidev(struct edd_device *edev)
+{
+	struct pci_dev *pci_dev;
+	int rc = -EINVAL;
+
+	pci_dev = edd_get_pci_dev(edev);
+	if (pci_dev) {
+		struct scsi_device * sdev = edd_find_matching_scsi_device(edev);
+		if (sdev && get_device(&sdev->sdev_driverfs_dev)) {
+			rc = sysfs_create_link(&edev->kobj,
+					       &sdev->sdev_driverfs_dev.kobj,
+					       "disc");
+			put_device(&sdev->sdev_driverfs_dev);
+		}
+	}
+	return rc;
+}
+
+#else
+static int
+edd_create_symlink_to_scsidev(struct edd_device *edev)
+{
+	return -ENOSYS;
+}
+#endif
+
+
+static inline void
+edd_device_unregister(struct edd_device *edev)
+{
+	kobject_unregister(&edev->kobj);
+}
+
+static void edd_populate_dir(struct edd_device * edev)
+{
+	struct edd_attribute * attr;
+	int error = 0;
+	int i;
+
+	for (i = 0; (attr = edd_attrs[i]) && !error; i++) {
+		if (!attr->test ||
+		    (attr->test && attr->test(edev)))
+			error = sysfs_create_file(&edev->kobj,&attr->attr);
+	}
+
+	if (!error) {
+		edd_create_symlink_to_pcidev(edev);
+		edd_create_symlink_to_scsidev(edev);
+	}
+}
+
+static int
+edd_device_register(struct edd_device *edev, int i)
+{
+	int error;
+
+	if (!edev)
+		return 1;
+	memset(edev, 0, sizeof (*edev));
+	edd_dev_set_info(edev, &edd[i]);
+	snprintf(edev->kobj.name, EDD_DEVICE_NAME_SIZE, "int13_dev%02x",
+		 edd[i].device);
+	kobj_set_kset_s(edev,edd_subsys);
+	error = kobject_register(&edev->kobj);
+	if (!error)
+		edd_populate_dir(edev);
+	return error;
+}
+
+/**
+ * edd_init() - creates sysfs tree of EDD data
+ *
+ * This assumes that eddnr and edd were
+ * assigned in setup.c already.
+ */
+static int __init
+edd_init(void)
+{
+	unsigned int i;
+	int rc=0;
+	struct edd_device *edev;
+
+	printk(KERN_INFO "BIOS EDD facility v%s, %d devices found\n",
+	       EDD_VERSION, eddnr);
+	printk(KERN_INFO "Please report your BIOS at %s\n", REPORT_URL);
+
+	if (!eddnr) {
+		printk(KERN_INFO "EDD information not available.\n");
+		return 1;
+	}
+
+	rc = firmware_register(&edd_subsys);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < eddnr && i < EDDMAXNR && !rc; i++) {
+		edev = kmalloc(sizeof (*edev), GFP_KERNEL);
+		if (!edev)
+			return -ENOMEM;
+
+		rc = edd_device_register(edev, i);
+		if (rc) {
+			kfree(edev);
+			break;
+		}
+		edd_devices[i] = edev;
+	}
+
+	if (rc)
+		firmware_unregister(&edd_subsys);
+	return rc;
+}
+
+static void __exit
+edd_exit(void)
+{
+	int i;
+	struct edd_device *edev;
+
+	for (i = 0; i < eddnr && i < EDDMAXNR; i++) {
+		if ((edev = edd_devices[i]))
+			edd_device_unregister(edev);
+	}
+	firmware_unregister(&edd_subsys);
+}
+
+late_initcall(edd_init);
+module_exit(edd_exit);
diff -Nru a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
--- a/drivers/i2c/Kconfig	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/Kconfig	Sat Apr  3 19:38:42 2004
@@ -15,9 +15,6 @@
 
 	  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.
@@ -48,6 +45,15 @@
 	  Say Y here if you want the I2C core to produce a bunch of debug
 	  messages to the system log.  Select this if you are having a
 	  problem with I2C support and want to see more of what is going on.
+
+config I2C_DEBUG_ALGO
+	bool "I2C Algorithm debugging messages"
+	depends on I2C
+	help
+	  Say Y here if you want the I2C algorithm drivers to produce a bunch
+	  of debug messages to the system log.  Select this if you are having
+	  a problem with I2C support and want to see more of what is going
+	  on.
 
 config I2C_DEBUG_BUS
 	bool "I2C Bus debugging messages"
diff -Nru a/drivers/i2c/Makefile b/drivers/i2c/Makefile
--- a/drivers/i2c/Makefile	Sat Apr  3 19:38:40 2004
+++ b/drivers/i2c/Makefile	Sat Apr  3 19:38:40 2004
@@ -6,3 +6,7 @@
 obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
 obj-$(CONFIG_I2C_SENSOR)	+= i2c-sensor.o
 obj-y				+= busses/ chips/ algos/
+
+ifeq ($(CONFIG_I2C_DEBUG_CORE),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -Nru a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
--- a/drivers/i2c/algos/Makefile	Sat Apr  3 19:38:54 2004
+++ b/drivers/i2c/algos/Makefile	Sat Apr  3 19:38:54 2004
@@ -5,3 +5,7 @@
 obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
 obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
 obj-$(CONFIG_I2C_ALGOITE)	+= i2c-algo-ite.o
+
+ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -Nru a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
--- a/drivers/i2c/algos/i2c-algo-bit.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/algos/i2c-algo-bit.c	Sat Apr  3 19:38:43 2004
@@ -21,8 +21,6 @@
 /* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
    <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
 
-/* #define DEBUG 1 */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
diff -Nru a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
--- a/drivers/i2c/algos/i2c-algo-pcf.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/i2c/algos/i2c-algo-pcf.c	Sat Apr  3 19:38:54 2004
@@ -27,8 +27,6 @@
    messages, proper stop/repstart signaling during receive,
    added detect code */
 
-/* #define DEBUG 1 */		/* to pick up dev_dbg calls */
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/drivers/i2c/busses/Kconfig	Sat Apr  3 19:38:55 2004
@@ -58,17 +58,6 @@
 	  This support is also available as a module.  If so, the module 
 	  will be called i2c-elektor.
 
-config I2C_ELV
-	tristate "ELV adapter"
-	depends on I2C
-	select I2C_ALGOBIT
-	help
-	  This supports parallel-port I2C adapters called ELV.  Say Y if you
-	  own such an adapter.
-
-	  This support is also available as a module.  If so, the module 
-	  will be called i2c-elv.
-
 config I2C_HYDRA
 	tristate "CHRP Apple Hydra Mac I/O I2C interface"
 	depends on I2C && PCI && PPC_CHRP && EXPERIMENTAL
@@ -144,6 +133,17 @@
 	  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
@@ -164,16 +164,6 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-nforce2.
 
-config I2C_PHILIPSPAR
-	tristate "Philips style parallel port adapter"
-	depends on I2C && PARPORT
-	select I2C_ALGOBIT
-	help
-	  This supports parallel-port I2C adapters made by Philips.
-
-	  This support is also available as a module.  If so, the module 
-	  will be called i2c-philips-par.
-
 config I2C_PARPORT
 	tristate "Parallel port adapter"
 	depends on I2C && PARPORT
@@ -342,17 +332,6 @@
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-sis96x.
-
-config I2C_VELLEMAN
-	tristate "Velleman K8000 adapter"
-	depends on I2C
-	select I2C_ALGOBIT
-	help
-	  This supports the Velleman K8000 parallel-port I2C adapter.  Say Y
-	  if you own such an adapter.
-
-	  This support is also available as a module.  If so, the module 
-	  will be called i2c-velleman.
 
 config I2C_VIA
 	tristate "VIA 82C586B"
diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
--- a/drivers/i2c/busses/Makefile	Sat Apr  3 19:38:41 2004
+++ b/drivers/i2c/busses/Makefile	Sat Apr  3 19:38:41 2004
@@ -7,7 +7,6 @@
 obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
 obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
 obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
-obj-$(CONFIG_I2C_ELV)		+= i2c-elv.o
 obj-$(CONFIG_I2C_HYDRA)		+= i2c-hydra.o
 obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
 obj-$(CONFIG_I2C_I810)		+= i2c-i810.o
@@ -15,9 +14,9 @@
 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
 obj-$(CONFIG_I2C_PARPORT)	+= i2c-parport.o
 obj-$(CONFIG_I2C_PARPORT_LIGHT)	+= i2c-parport-light.o
 obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
@@ -27,9 +26,12 @@
 obj-$(CONFIG_I2C_SIS5595)	+= i2c-sis5595.o
 obj-$(CONFIG_I2C_SIS630)	+= i2c-sis630.o
 obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
-obj-$(CONFIG_I2C_VELLEMAN)	+= i2c-velleman.o
 obj-$(CONFIG_I2C_VIA)		+= i2c-via.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
 obj-$(CONFIG_I2C_VOODOO3)	+= i2c-voodoo3.o
 obj-$(CONFIG_SCx200_ACB)	+= scx200_acb.o
 obj-$(CONFIG_SCx200_I2C)	+= scx200_i2c.o
+
+ifeq ($(CONFIG_I2C_DEBUG_BUS),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -Nru a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
--- a/drivers/i2c/busses/i2c-ali1535.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/i2c/busses/i2c-ali1535.c	Sat Apr  3 19:38:55 2004
@@ -54,10 +54,6 @@
 /* Note: we assume there can only be one ALI1535, with one SMBus interface */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
@@ -484,6 +480,7 @@
 
 static struct i2c_adapter ali1535_adapter = {
 	.owner		= THIS_MODULE,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.name		= "unset",
 };
@@ -517,6 +514,7 @@
 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 +532,6 @@
 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 -Nru a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
--- a/drivers/i2c/busses/i2c-ali15x3.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/busses/i2c-ali15x3.c	Sat Apr  3 19:38:43 2004
@@ -61,10 +61,6 @@
 /* Note: we assume there can only be one ALI15X3, with one SMBus interface */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
diff -Nru a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
--- a/drivers/i2c/busses/i2c-amd756.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/i2c/busses/i2c-amd756.c	Sat Apr  3 19:38:55 2004
@@ -38,10 +38,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
diff -Nru a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
--- a/drivers/i2c/busses/i2c-amd8111.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/i2c/busses/i2c-amd8111.c	Sat Apr  3 19:38:55 2004
@@ -9,10 +9,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
diff -Nru a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
--- a/drivers/i2c/busses/i2c-elektor.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/i2c/busses/i2c-elektor.c	Sat Apr  3 19:38:41 2004
@@ -26,10 +26,6 @@
    for Alpha Processor Inc. UP-2000(+) boards */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
diff -Nru a/drivers/i2c/busses/i2c-elv.c b/drivers/i2c/busses/i2c-elv.c
--- a/drivers/i2c/busses/i2c-elv.c	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,172 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/* i2c-elv.c i2c-hw access for philips style parallel port adapters	     */
-/* ------------------------------------------------------------------------- */
-/*   Copyright (C) 1995-2000 Simon G. Vogl
-
-    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.		     */
-/* ------------------------------------------------------------------------- */
-
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
-   Frodo Looijaard <frodol@dds.nl> */
-
-#include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/io.h>
-
-#define DEFAULT_BASE 0x378
-static long base=0;
-static unsigned char port_data = 0;
-
-/* --- Convenience defines for the parallel port:			*/
-#define BASE	(unsigned long)(data)
-#define DATA	BASE			/* Centronics data port		*/
-#define STAT	(BASE+1)		/* Centronics status port	*/
-#define CTRL	(BASE+2)		/* Centronics control port	*/
-
-
-/* ----- local functions ----------------------------------------------	*/
-
-
-static void bit_elv_setscl(void *data, int state)
-{
-	if (state) {
-		port_data &= 0xfe;
-	} else {
-		port_data |=1;
-	}
-	outb(port_data, DATA);
-}
-
-static void bit_elv_setsda(void *data, int state)
-{
-	if (state) {
-		port_data &=0xfd;
-	} else {
-		port_data |=2;
-	}
-	outb(port_data, DATA);
-} 
-
-static int bit_elv_getscl(void *data)
-{
-	return ( 0 == ( (inb_p(STAT)) & 0x08 ) );
-}
-
-static int bit_elv_getsda(void *data)
-{
-	return ( 0 == ( (inb_p(STAT)) & 0x40 ) );
-}
-
-static int bit_elv_init(void)
-{
-	if (!request_region(base, (base == 0x3bc) ? 3 : 8,
-				"i2c (ELV adapter)"))
-		return -ENODEV;
-
-	if (inb(base+1) & 0x80) {	/* BUSY should be high	*/
-		pr_debug("i2c-elv: Busy was low.\n");
-		goto fail;
-	} 
-
-	outb(0x0c,base+2);	/* SLCT auf low		*/
-	udelay(400);
-	if (!(inb(base+1) && 0x10)) {
-		outb(0x04,base+2);
-		pr_debug("i2c-elv: Select was high.\n");
-		goto fail;
-	}
-
-	port_data = 0;
-	bit_elv_setsda((void*)base,1);
-	bit_elv_setscl((void*)base,1);
-	return 0;
-
-fail:
-	release_region(base , (base == 0x3bc) ? 3 : 8);
-	return -ENODEV;
-}
-
-/* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
-static struct i2c_algo_bit_data bit_elv_data = {
-	.setsda		= bit_elv_setsda,
-	.setscl		= bit_elv_setscl,
-	.getsda		= bit_elv_getsda,
-	.getscl		= bit_elv_getscl,
-	.udelay		= 80,
-	.mdelay		= 80,
-	.timeout	= HZ
-};
-
-static struct i2c_adapter bit_elv_ops = {
-	.owner		= THIS_MODULE,
-	.algo_data	= &bit_elv_data,
-	.name		= "ELV Parallel port adaptor",
-};
-
-static int __init i2c_bitelv_init(void)
-{
-	printk(KERN_INFO "i2c ELV parallel port adapter driver\n");
-	if (base==0) {
-		/* probe some values */
-		base=DEFAULT_BASE;
-		bit_elv_data.data=(void*)DEFAULT_BASE;
-		if (bit_elv_init()==0) {
-			if(i2c_bit_add_bus(&bit_elv_ops) < 0)
-				return -ENODEV;
-		} else {
-			return -ENODEV;
-		}
-	} else {
-		i2c_set_adapdata(&bit_elv_ops, (void *)base);
-		if (bit_elv_init()==0) {
-			if(i2c_bit_add_bus(&bit_elv_ops) < 0)
-				return -ENODEV;
-		} else {
-			return -ENODEV;
-		}
-	}
-	pr_debug("i2c-elv: found device at %#lx.\n",base);
-	return 0;
-}
-
-static void __exit i2c_bitelv_exit(void)
-{
-	i2c_bit_del_bus(&bit_elv_ops);
-	release_region(base , (base == 0x3bc) ? 3 : 8);
-}
-
-MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(base, "i");
-
-module_init(i2c_bitelv_init);
-module_exit(i2c_bitelv_exit);
diff -Nru a/drivers/i2c/busses/i2c-frodo.c b/drivers/i2c/busses/i2c-frodo.c
--- a/drivers/i2c/busses/i2c-frodo.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/i2c/busses/i2c-frodo.c	Sat Apr  3 19:38:40 2004
@@ -13,10 +13,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff -Nru a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
--- a/drivers/i2c/busses/i2c-i801.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/busses/i2c-i801.c	Sat Apr  3 19:38:43 2004
@@ -39,10 +39,6 @@
 /* Note: we assume there can only be one I801, with one SMBus interface */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
@@ -608,6 +604,7 @@
 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 +622,6 @@
 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 -Nru a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c
--- a/drivers/i2c/busses/i2c-i810.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/i2c/busses/i2c-i810.c	Sat Apr  3 19:38:41 2004
@@ -35,10 +35,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
diff -Nru a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
--- a/drivers/i2c/busses/i2c-ibm_iic.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/i2c/busses/i2c-ibm_iic.c	Sat Apr  3 19:38:54 2004
@@ -29,10 +29,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
diff -Nru a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
--- a/drivers/i2c/busses/i2c-iop3xx.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/busses/i2c-iop3xx.c	Sat Apr  3 19:38:43 2004
@@ -32,10 +32,6 @@
   ---------------------------------------------------------------------------*/
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -129,7 +125,7 @@
  * 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 +138,7 @@
 		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 +182,7 @@
 	unsigned sr = 0;
 	int interrupted;
 	int done;
-	int rc;
+	int rc = 0;
 
 	do {
 		interrupted = wait_event_interruptible_timeout (
@@ -198,13 +195,13 @@
 			return rc;
 		}else if (!interrupted) {
 			*status = sr;
-			return rc = -ETIMEDOUT;
+			return -ETIMEDOUT;
 		}
 	} while(!done);
 
 	*status = sr;
 
-	return rc = 0;
+	return 0;
 }
 
 /*
@@ -284,7 +281,7 @@
 {
 	unsigned cr = *iop3xx_adap->biu->CR;
 	int status;
-	int rc;
+	int rc = 0;
 
 	*iop3xx_adap->biu->DBR = byte;
 	cr &= ~IOP321_ICR_MSTART;
@@ -304,7 +301,7 @@
 {
 	unsigned cr = *iop3xx_adap->biu->CR;
 	int status;
-	int rc;
+	int rc = 0;
 
 	cr &= ~IOP321_ICR_MSTART;
 
@@ -386,13 +383,16 @@
 	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 -Nru a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
--- a/drivers/i2c/busses/i2c-isa.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/i2c/busses/i2c-isa.c	Sat Apr  3 19:38:44 2004
@@ -25,10 +25,6 @@
    of this. */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff -Nru a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c
--- a/drivers/i2c/busses/i2c-ite.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/busses/i2c-ite.c	Sat Apr  3 19:38:42 2004
@@ -34,10 +34,6 @@
    Frodo Looijaard <frodol@dds.nl> */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
diff -Nru a/drivers/i2c/busses/i2c-ixp42x.c b/drivers/i2c/busses/i2c-ixp42x.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/busses/i2c-ixp42x.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,176 @@
+/*
+ * 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>
+#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 -Nru a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
--- a/drivers/i2c/busses/i2c-keywest.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/i2c/busses/i2c-keywest.c	Sat Apr  3 19:38:45 2004
@@ -47,10 +47,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -612,6 +608,7 @@
 	}
 #endif /* POLLED_MODE */
 
+	pmac_low_i2c_unlock(np);
 	dev_set_drvdata(dev, iface);
 	
 	for (i=0; i<nchan; i++) {
@@ -649,7 +646,6 @@
 	printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
 		np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps);
 		
-	pmac_low_i2c_unlock(np);
 	return 0;
 }
 
diff -Nru a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
--- a/drivers/i2c/busses/i2c-nforce2.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/i2c/busses/i2c-nforce2.c	Sat Apr  3 19:38:41 2004
@@ -33,10 +33,6 @@
 /* Note: we assume there can only be one nForce2, with two SMBus interfaces */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
diff -Nru a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
--- a/drivers/i2c/busses/i2c-parport-light.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/i2c/busses/i2c-parport-light.c	Sat Apr  3 19:38:55 2004
@@ -25,10 +25,6 @@
  * ------------------------------------------------------------------------ */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
diff -Nru a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
--- a/drivers/i2c/busses/i2c-parport.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/i2c/busses/i2c-parport.c	Sat Apr  3 19:38:44 2004
@@ -25,10 +25,6 @@
  * ------------------------------------------------------------------------ */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
diff -Nru a/drivers/i2c/busses/i2c-philips-par.c b/drivers/i2c/busses/i2c-philips-par.c
--- a/drivers/i2c/busses/i2c-philips-par.c	Sat Apr  3 19:38:41 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,246 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/* i2c-philips-par.c i2c-hw access for philips style parallel port adapters  */
-/* ------------------------------------------------------------------------- */
-/*   Copyright (C) 1995-2000 Simon G. Vogl
-
-    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.		     */
-/* ------------------------------------------------------------------------- */ 
-
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
-   Frodo Looijaard <frodol@dds.nl> */
-
-#include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-
-static int type;
-
-struct i2c_par
-{
-	struct pardevice *pdev;
-	struct i2c_adapter adapter;
-	struct i2c_algo_bit_data bit_lp_data;
-	struct i2c_par *next;
-};
-
-static struct i2c_par *adapter_list;
-
-
-/* ----- printer port defines ------------------------------------------*/
-					/* Pin Port  Inverted	name	*/
-#define I2C_ON		0x20		/* 12 status N	paper		*/
-					/* ... only for phil. not used  */
-#define I2C_SDA		0x80		/*  9 data   N	data7		*/
-#define I2C_SCL		0x08		/* 17 ctrl   N	dsel		*/
-
-#define I2C_SDAIN	0x80		/* 11 stat   Y	busy		*/
-#define I2C_SCLIN	0x08		/* 15 stat   Y	enable		*/
-
-#define I2C_DMASK	0x7f
-#define I2C_CMASK	0xf7
-
-/* ----- local functions ----------------------------------------------	*/
-
-static void bit_lp_setscl(void *data, int state)
-{
-	/*be cautious about state of the control register - 
-		touch only the one bit needed*/
-	if (state) {
-		parport_write_control((struct parport *) data,
-		      parport_read_control((struct parport *) data)|I2C_SCL);
-	} else {
-		parport_write_control((struct parport *) data,
-		      parport_read_control((struct parport *) data)&I2C_CMASK);
-	}
-}
-
-static void bit_lp_setsda(void *data, int state)
-{
-	if (state) {
-		parport_write_data((struct parport *) data, I2C_DMASK);
-	} else {
-		parport_write_data((struct parport *) data, I2C_SDA);
-	}
-}
-
-static int bit_lp_getscl(void *data)
-{
-	return parport_read_status((struct parport *) data) & I2C_SCLIN;
-}
-
-static int bit_lp_getsda(void *data)
-{
-	return parport_read_status((struct parport *) data) & I2C_SDAIN;
-}
-
-static void bit_lp_setscl2(void *data, int state)
-{
-	if (state) {
-		parport_write_data((struct parport *) data,
-		      parport_read_data((struct parport *) data)|0x1);
-	} else {
-		parport_write_data((struct parport *) data,
-		      parport_read_data((struct parport *) data)&0xfe);
-	}
-}
-
-static void bit_lp_setsda2(void *data, int state)
-{
-	if (state) {
-		parport_write_data((struct parport *) data,
-		      parport_read_data((struct parport *) data)|0x2);
-	} else {
-		parport_write_data((struct parport *) data,
-		      parport_read_data((struct parport *) data)&0xfd);
-	}
-}
-
-static int bit_lp_getsda2(void *data)
-{
-	return (parport_read_status((struct parport *) data) & 
-			             PARPORT_STATUS_BUSY) ? 0 : 1;
-}
-
-/* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
- 
-static struct i2c_algo_bit_data bit_lp_data = {
-	.setsda		= bit_lp_setsda,
-	.setscl		= bit_lp_setscl,
-	.getsda		= bit_lp_getsda,
-	.getscl		= bit_lp_getscl,
-	.udelay		= 80,
-	.mdelay		= 80,
-	.timeout	= HZ
-}; 
-
-static struct i2c_algo_bit_data bit_lp_data2 = {
-	.setsda		= bit_lp_setsda2,
-	.setscl		= bit_lp_setscl2,
-	.getsda		= bit_lp_getsda2,
-	.udelay		= 80,
-	.mdelay		= 80,
-	.timeout	= HZ
-}; 
-
-static struct i2c_adapter bit_lp_ops = {
-	.owner		= THIS_MODULE,
-	.id		= I2C_HW_B_LP,
-	.name		= "Philips Parallel port adapter",
-};
-
-static void i2c_parport_attach (struct parport *port)
-{
-	struct i2c_par *adapter = kmalloc(sizeof(struct i2c_par),
-					  GFP_KERNEL);
-	if (!adapter) {
-		printk(KERN_ERR "i2c-philips-par: Unable to malloc.\n");
-		return;
-	}
-	memset (adapter, 0x00, sizeof(struct i2c_par));
-
-	/* pr_debug("i2c-philips-par: attaching to %s\n", port->name); */
-
-	adapter->pdev = parport_register_device(port, "i2c-philips-par",
-						NULL, NULL, NULL, 
-						PARPORT_FLAG_EXCL,
-						NULL);
-	if (!adapter->pdev) {
-		printk(KERN_ERR "i2c-philips-par: Unable to register with parport.\n");
-		kfree(adapter);
-		return;
-	}
-
-	adapter->adapter = bit_lp_ops;
-	adapter->adapter.algo_data = &adapter->bit_lp_data;
-	adapter->bit_lp_data = type ? bit_lp_data2 : bit_lp_data;
-	adapter->bit_lp_data.data = port;
-
-	if (parport_claim_or_block(adapter->pdev) < 0 ) {
-		printk(KERN_ERR "i2c-philips-par: Could not claim parallel port.\n");
-		kfree(adapter);
-		return;
-	}
-	/* reset hardware to sane state */
-	adapter->bit_lp_data.setsda(port, 1);
-	adapter->bit_lp_data.setscl(port, 1);
-	parport_release(adapter->pdev);
-
-	if (i2c_bit_add_bus(&adapter->adapter) < 0) {
-		printk(KERN_ERR "i2c-philips-par: Unable to register with I2C.\n");
-		parport_unregister_device(adapter->pdev);
-		kfree(adapter);
-		return;		/* No good */
-	}
-
-	adapter->next = adapter_list;
-	adapter_list = adapter;
-}
-
-static void i2c_parport_detach (struct parport *port)
-{
-	struct i2c_par *adapter, *prev = NULL;
-
-	for (adapter = adapter_list; adapter; adapter = adapter->next) {
-		if (adapter->pdev->port == port) {
-			parport_unregister_device(adapter->pdev);
-			i2c_bit_del_bus(&adapter->adapter);
-			if (prev)
-				prev->next = adapter->next;
-			else
-				adapter_list = adapter->next;
-			kfree(adapter);
-			return;
-		}
-		prev = adapter;
-	}
-}
-
-static struct parport_driver i2c_driver = {
-	.name =		"i2c-philips-par",
-	.attach =	i2c_parport_attach,
-	.detach =	i2c_parport_detach,
-};
-
-int __init i2c_bitlp_init(void)
-{
-	printk(KERN_INFO "i2c Philips parallel port adapter driver\n");
-
-	return parport_register_driver(&i2c_driver);
-}
-
-void __exit i2c_bitlp_exit(void)
-{
-	parport_unregister_driver(&i2c_driver);
-}
-
-MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for Philips parallel port adapter");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(type, "i");
-
-module_init(i2c_bitlp_init);
-module_exit(i2c_bitlp_exit);
diff -Nru a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
--- a/drivers/i2c/busses/i2c-piix4.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/busses/i2c-piix4.c	Sat Apr  3 19:38:42 2004
@@ -29,10 +29,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/config.h>
diff -Nru a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c
--- a/drivers/i2c/busses/i2c-prosavage.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/busses/i2c-prosavage.c	Sat Apr  3 19:38:42 2004
@@ -55,10 +55,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pci.h>
@@ -216,7 +212,7 @@
 /*
  * 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 +317,7 @@
 	.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 -Nru a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c
--- a/drivers/i2c/busses/i2c-rpx.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/i2c/busses/i2c-rpx.c	Sat Apr  3 19:38:56 2004
@@ -12,10 +12,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
diff -Nru a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
--- a/drivers/i2c/busses/i2c-savage4.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/busses/i2c-savage4.c	Sat Apr  3 19:38:43 2004
@@ -30,10 +30,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
diff -Nru a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
--- a/drivers/i2c/busses/i2c-sis5595.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/busses/i2c-sis5595.c	Sat Apr  3 19:38:42 2004
@@ -56,10 +56,6 @@
  */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -364,6 +360,7 @@
 
 static struct i2c_adapter sis5595_adapter = {
 	.owner		= THIS_MODULE,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.name		= "unset",
 	.algo		= &smbus_algorithm,
 };
@@ -391,6 +388,7 @@
 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 +406,6 @@
 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 -Nru a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
--- a/drivers/i2c/busses/i2c-sis630.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/busses/i2c-sis630.c	Sat Apr  3 19:38:42 2004
@@ -49,10 +49,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
diff -Nru a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
--- a/drivers/i2c/busses/i2c-sis96x.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/busses/i2c-sis96x.c	Sat Apr  3 19:38:42 2004
@@ -33,10 +33,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
diff -Nru a/drivers/i2c/busses/i2c-velleman.c b/drivers/i2c/busses/i2c-velleman.c
--- a/drivers/i2c/busses/i2c-velleman.c	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,158 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/* i2c-velleman.c i2c-hw access for Velleman K8000 adapters		     */
-/* ------------------------------------------------------------------------- */
-/*   Copyright (C) 1995-96, 2000 Simon G. Vogl
-
-    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_BUS
-#define DEBUG	1
-#endif
-
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
-#include <asm/io.h>
-
-					/* Pin Port  Inverted	name	*/
-#define I2C_SDA		0x02		/*  ctrl bit 1 	(inv)	*/
-#define I2C_SCL		0x08		/*  ctrl bit 3 	(inv)	*/
-
-#define I2C_SDAIN	0x10		/* stat bit 4		*/
-#define I2C_SCLIN	0x08		/* ctrl bit 3 (inv)(reads own output)*/
-
-#define I2C_DMASK	0xfd
-#define I2C_CMASK	0xf7
-
-
-/* --- Convenience defines for the parallel port:			*/
-#define BASE	(unsigned long)(data)
-#define DATA	BASE			/* Centronics data port		*/
-#define STAT	(BASE+1)		/* Centronics status port	*/
-#define CTRL	(BASE+2)		/* Centronics control port	*/
-
-#define DEFAULT_BASE 0x378
-static long base=0;
-
-/* ----- local functions --------------------------------------------------- */
-
-static void bit_velle_setscl(void *data, int state)
-{
-	if (state) {
-		outb(inb(CTRL) & I2C_CMASK,   CTRL);
-	} else {
-		outb(inb(CTRL) | I2C_SCL, CTRL);
-	}
-	
-}
-
-static void bit_velle_setsda(void *data, int state)
-{
-	if (state) {
-		outb(inb(CTRL) & I2C_DMASK , CTRL);
-	} else {
-		outb(inb(CTRL) | I2C_SDA, CTRL);
-	}
-	
-} 
-
-static int bit_velle_getscl(void *data)
-{
-	return ( 0 == ( (inb(CTRL)) & I2C_SCLIN ) );
-}
-
-static int bit_velle_getsda(void *data)
-{
-	return ( 0 != ( (inb(STAT)) & I2C_SDAIN ) );
-}
-
-static int bit_velle_init(void)
-{
-	if (!request_region(base, (base == 0x3bc) ? 3 : 8, 
-			"i2c (Vellemann adapter)"))
-		return -ENODEV;
-
-	bit_velle_setsda((void*)base,1);
-	bit_velle_setscl((void*)base,1);
-	return 0;
-}
-
-/* ------------------------------------------------------------------------
- * Encapsulate the above functions in the correct operations structure.
- * This is only done when more than one hardware adapter is supported.
- */
-
-static struct i2c_algo_bit_data bit_velle_data = {
-	.setsda		= bit_velle_setsda,
-	.setscl		= bit_velle_setscl,
-	.getsda		= bit_velle_getsda,
-	.getscl		= bit_velle_getscl,
-	.udelay		= 10,
-	.mdelay		= 10,
-	.timeout	= HZ
-};
-
-static struct i2c_adapter bit_velle_ops = {
-	.owner		= THIS_MODULE,
-	.algo_data	= &bit_velle_data,
-	.name		= "Velleman K8000",
-};
-
-static int __init i2c_bitvelle_init(void)
-{
-	printk(KERN_INFO "i2c-velleman: i2c Velleman K8000 driver\n");
-	if (base==0) {
-		/* probe some values */
-		base=DEFAULT_BASE;
-		bit_velle_data.data=(void*)DEFAULT_BASE;
-		if (bit_velle_init()==0) {
-			if(i2c_bit_add_bus(&bit_velle_ops) < 0)
-				return -ENODEV;
-		} else {
-			return -ENODEV;
-		}
-	} else {
-		bit_velle_data.data=(void*)base;
-		if (bit_velle_init()==0) {
-			if(i2c_bit_add_bus(&bit_velle_ops) < 0)
-				return -ENODEV;
-		} else {
-			return -ENODEV;
-		}
-	}
-	pr_debug("i2c-velleman: found device at %#lx.\n",base);
-	return 0;
-}
-
-static void __exit i2c_bitvelle_exit(void)
-{	
-	i2c_bit_del_bus(&bit_velle_ops);
-	release_region(base, (base == 0x3bc) ? 3 : 8);
-}
-
-MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(base, "i");
-
-module_init(i2c_bitvelle_init);
-module_exit(i2c_bitvelle_exit);
diff -Nru a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
--- a/drivers/i2c/busses/i2c-via.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/busses/i2c-via.c	Sat Apr  3 19:38:43 2004
@@ -22,10 +22,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -92,6 +88,7 @@
 
 static struct i2c_adapter vt586b_adapter = {
 	.owner		= THIS_MODULE,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.name		= "VIA i2c",
 	.algo_data	= &bit_data,
 };
diff -Nru a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
--- a/drivers/i2c/busses/i2c-viapro.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/i2c/busses/i2c-viapro.c	Sat Apr  3 19:38:54 2004
@@ -34,10 +34,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
diff -Nru a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
--- a/drivers/i2c/busses/i2c-voodoo3.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/busses/i2c-voodoo3.c	Sat Apr  3 19:38:43 2004
@@ -28,10 +28,6 @@
     the BT869 and possibly other I2C devices. */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -171,6 +167,7 @@
 
 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 +184,7 @@
 
 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 -Nru a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
--- a/drivers/i2c/busses/scx200_acb.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/busses/scx200_acb.c	Sat Apr  3 19:38:43 2004
@@ -25,10 +25,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
diff -Nru a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
--- a/drivers/i2c/busses/scx200_i2c.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/busses/scx200_i2c.c	Sat Apr  3 19:38:43 2004
@@ -22,10 +22,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_BUS
-#define DEBUG	1
-#endif
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
--- a/drivers/i2c/chips/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/chips/Kconfig	Sat Apr  3 19:38:43 2004
@@ -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,17 +33,16 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called asb100.
 
-config SENSORS_EEPROM
-	tristate "EEPROM (DIMM) reader"
+config SENSORS_DS1621
+      	tristate "Dallas Semiconductor DS1621 and DS1625"
 	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.
+	  If you say yes here you get support for Dallas Semiconductor
+	  DS1621 and DS1625 sensor chips. 
 
 	  This driver can also be built as a module.  If so, the module
-	  will be called eeprom.
+	  will be called ds1621.
 
 config SENSORS_FSCHER
 	tristate "FSC Hermes"
@@ -102,6 +101,17 @@
 	  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
@@ -170,5 +180,33 @@
 	  
 	  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 -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
--- a/drivers/i2c/chips/Makefile	Sat Apr  3 19:38:57 2004
+++ b/drivers/i2c/chips/Makefile	Sat Apr  3 19:38:57 2004
@@ -4,17 +4,24 @@
 
 # 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
+obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
 obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
 obj-$(CONFIG_SENSORS_FSCHER)	+= fscher.o
 obj-$(CONFIG_SENSORS_GL518SM)	+= gl518sm.o
 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
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
 obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
+
+ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c
--- a/drivers/i2c/chips/adm1021.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/i2c/chips/adm1021.c	Sat Apr  3 19:38:40 2004
@@ -20,10 +20,6 @@
 */
 
 #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>
@@ -139,7 +135,7 @@
 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 +144,7 @@
 /* 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 +157,10 @@
 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 +170,10 @@
 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 +194,12 @@
 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);
 
@@ -309,10 +297,6 @@
 		type_name = "gl523sm";
 	} else if (kind == mc1066) {
 		type_name = "mc1066";
-	} else {
-		dev_err(&adapter->dev, "Internal error: unknown kind (%d)?!?",
-			kind);
-		goto error1;
 	}
 
 	/* Fill in the remaining client fields and put it into the global list */
@@ -331,12 +315,12 @@
 	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 +377,9 @@
 	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 +409,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_adm1021_init(void)
diff -Nru a/drivers/i2c/chips/asb100.c b/drivers/i2c/chips/asb100.c
--- a/drivers/i2c/chips/asb100.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/chips/asb100.c	Sat Apr  3 19:38:43 2004
@@ -37,10 +37,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_CHIP
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/ioport.h>
@@ -274,7 +270,7 @@
 { \
 	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 +292,9 @@
 { \
 	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 +306,9 @@
 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 +408,11 @@
 { \
 	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 +420,9 @@
 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 +480,7 @@
 { \
 	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 +490,7 @@
 { \
 	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 +501,7 @@
 { \
 	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 +511,9 @@
 
 /* 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 +522,9 @@
 	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 +593,12 @@
 	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 -Nru a/drivers/i2c/chips/ds1621.c b/drivers/i2c/chips/ds1621.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/chips/ds1621.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,345 @@
+/*
+    ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
+             monitoring
+    Christian W. Zuckschwerdt  <zany@triq.net>  2000-11-23
+    based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+    Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with 
+    the help of Jean Delvare <khali@linux-fr.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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include "lm75.h"
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 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(ds1621);
+static int polarity = -1;
+MODULE_PARM(polarity, "i");
+MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low");
+
+/* Many DS1621 constants specified below */
+/* Config register used for detection         */
+/*  7    6    5    4    3    2    1    0      */
+/* |Done|THF |TLF |NVB | 1  | 0  |POL |1SHOT| */
+#define DS1621_REG_CONFIG_MASK		0x0C
+#define DS1621_REG_CONFIG_VAL		0x08
+#define DS1621_REG_CONFIG_POLARITY	0x02
+#define DS1621_REG_CONFIG_1SHOT		0x01
+#define DS1621_REG_CONFIG_DONE		0x80
+
+/* The DS1621 registers */
+#define DS1621_REG_TEMP			0xAA /* word, RO */
+#define DS1621_REG_TEMP_MIN		0xA1 /* word, RW */
+#define DS1621_REG_TEMP_MAX		0xA2 /* word, RW */
+#define DS1621_REG_CONF			0xAC /* byte, RW */
+#define DS1621_COM_START		0xEE /* no data */
+
+/* The DS1621 configuration register */
+#define DS1621_ALARM_TEMP_HIGH		0x40
+#define DS1621_ALARM_TEMP_LOW		0x20
+
+/* 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 ALARMS_FROM_REG(val) ((val) & \
+                              (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
+
+/* Each client has this additional data */
+struct ds1621_data {
+	struct semaphore update_lock;
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	u16 temp, temp_min, temp_max;	/* Register values, word */
+	u8 conf;			/* Register encoding, combined */
+};
+
+static int ds1621_attach_adapter(struct i2c_adapter *adapter);
+static int ds1621_detect(struct i2c_adapter *adapter, int address,
+			 int kind);
+static void ds1621_init_client(struct i2c_client *client);
+static int ds1621_detach_client(struct i2c_client *client);
+static struct ds1621_data *ds1621_update_client(struct device *dev);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ds1621_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "ds1621",
+	.id		= I2C_DRIVERID_DS1621,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= ds1621_attach_adapter,
+	.detach_client	= ds1621_detach_client,
+};
+
+static int ds1621_id = 0;
+
+static u16 swap_bytes(u16 val)
+{
+	return (val >> 8) | (val << 8);
+}
+
+/* All registers are word-sized, except for the configuration register.
+   DS1621 uses a high-byte first convention, which is exactly opposite to
+   the usual practice. */
+static int ds1621_read_value(struct i2c_client *client, u8 reg)
+{
+	if (reg == DS1621_REG_CONF)
+		return i2c_smbus_read_byte_data(client, reg);
+	else
+		return swap_bytes(i2c_smbus_read_word_data(client, reg));
+}
+
+/* All registers are word-sized, except for the configuration register.
+   DS1621 uses a high-byte first convention, which is exactly opposite to
+   the usual practice. */
+static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
+{
+	if (reg == DS1621_REG_CONF)
+		return i2c_smbus_write_byte_data(client, reg, value);
+	else
+		return i2c_smbus_write_word_data(client, reg,
+						 swap_bytes(value));
+}
+
+static void ds1621_init_client(struct i2c_client *client)
+{
+	int reg = ds1621_read_value(client, DS1621_REG_CONF);
+	/* switch to continous conversion mode */
+	reg &= ~ DS1621_REG_CONFIG_1SHOT;
+
+	/* setup output polarity */
+	if (polarity == 0)
+		reg &= ~DS1621_REG_CONFIG_POLARITY;
+	else if (polarity == 1)
+		reg |= DS1621_REG_CONFIG_POLARITY;
+	
+	ds1621_write_value(client, DS1621_REG_CONF, reg);
+	
+	/* start conversion */
+	i2c_smbus_write_byte(client, DS1621_COM_START);
+}
+
+#define show(value)							\
+static ssize_t show_##value(struct device *dev, char *buf)		\
+{									\
+	struct ds1621_data *data = ds1621_update_client(dev);		\
+	return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value));	\
+}
+
+show(temp);
+show(temp_min);
+show(temp_max);
+
+#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 ds1621_data *data = ds1621_update_client(dev);		\
+	data->value = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));	\
+	ds1621_write_value(client, reg, data->value);			\
+	return count;							\
+}
+
+set_temp(min, temp_min, DS1621_REG_TEMP_MIN);
+set_temp(max, temp_max, DS1621_REG_TEMP_MAX);
+
+static ssize_t show_alarms(struct device *dev, char *buf)
+{
+	struct ds1621_data *data = ds1621_update_client(dev);
+	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+
+
+static int ds1621_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_detect(adapter, &addr_data, ds1621_detect);
+}
+
+/* This function is called by i2c_detect */
+int ds1621_detect(struct i2c_adapter *adapter, int address,
+                  int kind)
+{
+	int conf, temp;
+	struct i2c_client *new_client;
+	struct ds1621_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA 
+				     | I2C_FUNC_SMBUS_WORD_DATA 
+				     | I2C_FUNC_SMBUS_WRITE_BYTE))
+		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 ds1621_{read,write}_value. */
+	if (!(new_client = kmalloc(sizeof(struct i2c_client) +
+				   sizeof(struct ds1621_data),
+				   GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(new_client, 0, sizeof(struct i2c_client) +
+	       sizeof(struct ds1621_data));
+	
+	data = (struct ds1621_data *) (new_client + 1);
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &ds1621_driver;
+	new_client->flags = 0;
+
+
+	/* Now, we do the remaining detection. It is lousy. */
+	if (kind < 0) {
+		conf = ds1621_read_value(new_client, DS1621_REG_CONF);
+		if ((conf & DS1621_REG_CONFIG_MASK) != DS1621_REG_CONFIG_VAL)
+			goto exit_free;
+		temp = ds1621_read_value(new_client, DS1621_REG_TEMP);
+		if (temp & 0x007f)
+			goto exit_free;
+		temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN);
+		if (temp & 0x007f)
+			goto exit_free;
+		temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX);
+		if (temp & 0x007f)
+			goto exit_free;
+	}
+
+	/* Determine the chip type - only one kind supported! */
+	if (kind <= 0)
+		kind = ds1621;
+
+	/* Fill in remaining client fields and put it into the global list */
+	strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE);
+
+	new_client->id = ds1621_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 exit_free;
+
+	/* Initialize the DS1621 chip */
+	ds1621_init_client(new_client);
+
+	/* Register sysfs hooks */
+	device_create_file(&new_client->dev, &dev_attr_alarms);
+	device_create_file(&new_client->dev, &dev_attr_temp1_input);
+	device_create_file(&new_client->dev, &dev_attr_temp1_min);
+	device_create_file(&new_client->dev, &dev_attr_temp1_max);
+	
+	return 0;
+
+/* OK, this is not exactly good programming practice, usually. But it is
+   very code-efficient in this case. */
+      exit_free:
+	kfree(new_client);
+      exit:
+	return err;
+}
+
+static int ds1621_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev,
+		        "ds1621.o: Client deregistration failed, client not detached.\n");
+		return err;
+	}
+
+	kfree(client);
+
+	return 0;
+}
+
+
+static struct ds1621_data *ds1621_update_client(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ds1621_data *data = i2c_get_clientdata(client);
+	u8 new_conf;
+
+	down(&data->update_lock);
+
+	if ((jiffies - data->last_updated > HZ + HZ / 2) ||
+	    (jiffies < data->last_updated) || !data->valid) {
+
+		dev_dbg(&client->dev, "Starting ds1621 update\n");
+
+		data->conf = ds1621_read_value(client, DS1621_REG_CONF);
+
+		data->temp = ds1621_read_value(client, DS1621_REG_TEMP);
+		
+		data->temp_min = ds1621_read_value(client,
+		                                    DS1621_REG_TEMP_MIN);
+		data->temp_max = ds1621_read_value(client,
+						    DS1621_REG_TEMP_MAX);
+
+		/* reset alarms if neccessary */
+		new_conf = data->conf;
+		if (data->temp < data->temp_min)
+			new_conf &= ~DS1621_ALARM_TEMP_LOW;
+		if (data->temp > data->temp_max)
+			new_conf &= ~DS1621_ALARM_TEMP_HIGH;
+		if (data->conf != new_conf)
+			ds1621_write_value(client, DS1621_REG_CONF,
+					   new_conf);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	up(&data->update_lock);
+
+	return data;
+}
+
+static int __init ds1621_init(void)
+{
+	return i2c_add_driver(&ds1621_driver);
+}
+
+static void __exit ds1621_exit(void)
+{
+	i2c_del_driver(&ds1621_driver);
+}
+
+
+MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>");
+MODULE_DESCRIPTION("DS1621 driver");
+MODULE_LICENSE("GPL");
+
+module_init(ds1621_init);
+module_exit(ds1621_exit);
diff -Nru a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
--- a/drivers/i2c/chips/eeprom.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/chips/eeprom.c	Sat Apr  3 19:38:42 2004
@@ -27,10 +27,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_CHIP
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
diff -Nru a/drivers/i2c/chips/fscher.c b/drivers/i2c/chips/fscher.c
--- a/drivers/i2c/chips/fscher.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/chips/fscher.c	Sat Apr  3 19:38:43 2004
@@ -26,6 +26,7 @@
  *  and Philip Edelbrock <phil@netroedge.com>
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -108,7 +109,7 @@
 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 +161,69 @@
  * 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 +247,21 @@
   
 #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 +414,9 @@
 	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 +461,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 
@@ -484,7 +486,7 @@
 	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 +495,7 @@
 	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 -Nru a/drivers/i2c/chips/gl518sm.c b/drivers/i2c/chips/gl518sm.c
--- a/drivers/i2c/chips/gl518sm.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/i2c/chips/gl518sm.c	Sat Apr  3 19:38:56 2004
@@ -37,10 +37,6 @@
  */
 
 #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>
@@ -151,7 +147,7 @@
 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 +172,14 @@
 #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 +299,29 @@
 	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);
@@ -353,7 +345,6 @@
 	struct i2c_client *new_client;
 	struct gl518_data *data;
 	int err = 0;
-	const char *name = "";
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
 				     I2C_FUNC_SMBUS_WORD_DATA))
@@ -393,10 +384,8 @@
 		i = gl518_read_value(new_client, GL518_REG_REVISION);
 		if (i == 0x00) {
 			kind = gl518sm_r00;
-			name = "gl518sm";
 		} else if (i == 0x80) {
 			kind = gl518sm_r80;
-			name = "gl518sm";
 		} else {
 			if (kind <= 0)
 				dev_info(&adapter->dev,
@@ -408,7 +397,7 @@
 	}
 
 	/* Fill in the remaining client fields */
-	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+	strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE);
 	new_client->id = gl518_id++;
 	data->type = kind;
 	data->valid = 0;
@@ -424,28 +413,28 @@
 	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 +512,9 @@
 		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 +580,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_gl518sm_init(void)
diff -Nru a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c
--- a/drivers/i2c/chips/it87.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/i2c/chips/it87.c	Sat Apr  3 19:38:54 2004
@@ -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
@@ -32,10 +32,6 @@
 */
 
 #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>
@@ -51,17 +47,14 @@
 static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
 
 /* Insmod parameters */
-SENSORS_INSMOD_4(it87, it8705, it8712, sis950);
+SENSORS_INSMOD_1(it87);
 
 
 /* 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 +128,6 @@
 }
 #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 +163,13 @@
 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 +180,19 @@
 
 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 +225,7 @@
 {								\
 	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 +248,9 @@
 {								\
 	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 +274,17 @@
 /* 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 +332,10 @@
 {									\
 	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 +344,12 @@
 
 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 +360,13 @@
 
 	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 +380,7 @@
 {									\
 	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 +390,19 @@
 /* 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 +475,10 @@
 {									\
 	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 +488,7 @@
 /* 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);
@@ -681,12 +600,6 @@
 
 	if (kind == it87) {
 		name = "it87";
-	} /* else if (kind == it8712) {
-		name = "it8712";
-	} */ else {
-		dev_dbg(&adapter->dev, "Internal error: unknown kind (%d)?!?",
-			kind);
-		goto ERROR1;
 	}
 
 	/* Fill in the remaining client fields and put it into the global list */
@@ -706,52 +619,52 @@
 	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 +738,50 @@
 		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;
 
@@ -949,13 +827,7 @@
 		}
 
 		/* The 8705 does not have VID capability */
-		/*if (data->type == it8712) {
-			data->vid = it87_read_value(client, IT87_REG_VID);
-			data->vid &= 0x1f;
-		}
-		else */ {
-			data->vid = 0x1f;
-		}
+		data->vid = 0x1f;
 
 		i = it87_read_value(client, IT87_REG_FAN_DIV);
 		data->fan_div[0] = i & 0x07;
@@ -967,11 +839,15 @@
 			(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 +865,8 @@
 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 -Nru a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c
--- a/drivers/i2c/chips/lm75.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/i2c/chips/lm75.c	Sat Apr  3 19:38:40 2004
@@ -19,10 +19,6 @@
 */
 
 #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>
@@ -64,7 +60,7 @@
 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 +78,7 @@
 #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 +98,9 @@
 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)
 {
@@ -122,7 +116,7 @@
 	struct i2c_client *new_client;
 	struct lm75_data *data;
 	int err = 0;
-	const char *name;
+	const char *name = "";
 
 	/* Make sure we aren't probing the ISA bus!! This is just a safety check
 	   at this moment; i2c_detect really won't call us. */
@@ -176,10 +170,6 @@
 
 	if (kind == lm75) {
 		name = "lm75";
-	} else {
-		dev_dbg(&adapter->dev, "Internal error: unknown kind (%d)?!?",
-			kind);
-		goto exit_free;
 	}
 
 	/* Fill in the remaining client fields and put it into the global list */
@@ -197,9 +187,9 @@
 	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 +240,9 @@
 	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 +259,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_lm75_init(void)
diff -Nru a/drivers/i2c/chips/lm78.c b/drivers/i2c/chips/lm78.c
--- a/drivers/i2c/chips/lm78.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/i2c/chips/lm78.c	Sat Apr  3 19:38:55 2004
@@ -19,10 +19,6 @@
 */
 
 #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>
@@ -223,7 +219,7 @@
 
 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 +235,19 @@
 /* 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 +279,7 @@
 {								\
 	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 +301,9 @@
 {								\
 	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 +317,13 @@
 /* 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 +339,7 @@
 
 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 +353,23 @@
 	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 +387,7 @@
 
 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 +438,8 @@
 {									\
 	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 +459,24 @@
 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);
@@ -635,11 +609,6 @@
 		client_name = "lm78-j";
 	} else if (kind == lm79) {
 		client_name = "lm79";
-	} else {
-		dev_dbg(&adapter->dev, "Internal error: unknown kind (%d)?!?",
-			kind);
-		err = -ENODEV;
-		goto ERROR2;
 	}
 
 	/* Fill in the remaining client fields and put into the global list */
@@ -657,41 +626,41 @@
 	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 +798,9 @@
 
 }
 
-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 +849,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sm_lm78_init(void)
diff -Nru a/drivers/i2c/chips/lm80.c b/drivers/i2c/chips/lm80.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/chips/lm80.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,554 @@
+/*
+ * 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>
+#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 -Nru a/drivers/i2c/chips/lm83.c b/drivers/i2c/chips/lm83.c
--- a/drivers/i2c/chips/lm83.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/chips/lm83.c	Sat Apr  3 19:38:43 2004
@@ -28,10 +28,6 @@
  */
 
 #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>
@@ -118,7 +114,7 @@
 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 +158,7 @@
 #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 +189,21 @@
 
 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);
@@ -292,7 +284,6 @@
 		if (man_id == 0x01) { /* National Semiconductor */
 			if (chip_id == 0x03) {
 				kind = lm83;
-				name = "lm83";
 			}
 		}
 
@@ -304,6 +295,10 @@
 		}
 	}
 
+	if (kind == lm83) {
+		name = "lm83";
+	}
+
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	new_client->id = lm83_id++;
@@ -320,14 +315,14 @@
 	 */
 
 	/* 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 +348,9 @@
 	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 +381,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_lm83_init(void)
diff -Nru a/drivers/i2c/chips/lm85.c b/drivers/i2c/chips/lm85.c
--- a/drivers/i2c/chips/lm85.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/chips/lm85.c	Sat Apr  3 19:38:42 2004
@@ -23,10 +23,6 @@
 */
 
 #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>
@@ -397,7 +393,7 @@
 
 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 +413,12 @@
 /* 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 +450,8 @@
 {									\
 	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 +463,15 @@
 
 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 +490,7 @@
 
 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 +500,7 @@
 
 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 +519,9 @@
 }
 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 +540,9 @@
 {									\
 	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 +552,12 @@
 
 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 +576,7 @@
 }
 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 +616,10 @@
 {									\
 	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 +632,12 @@
 
 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 +656,7 @@
 }
 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 +696,10 @@
 {									\
 	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);
@@ -857,10 +815,6 @@
 		type_name = "adm1027";
 	} else if ( kind == adt7463 ) {
 		type_name = "adt7463";
-	} else {
-		dev_dbg(&adapter->dev, "Internal error, invalid kind (%d)!", kind);
-		err = -EFAULT ;
-		goto ERROR1;
 	}
 	strlcpy(new_client->name, type_name, I2C_NAME_SIZE);
 
@@ -886,46 +840,46 @@
 	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 +1001,9 @@
 	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 +1144,8 @@
 	data->valid = 1;
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 
diff -Nru a/drivers/i2c/chips/lm90.c b/drivers/i2c/chips/lm90.c
--- a/drivers/i2c/chips/lm90.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/i2c/chips/lm90.c	Sat Apr  3 19:38:41 2004
@@ -36,10 +36,6 @@
  */
 
 #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>
@@ -126,7 +122,7 @@
 	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 +167,7 @@
 #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 +210,7 @@
 #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 +231,27 @@
 
 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);
 
 /*
@@ -347,7 +337,6 @@
 				LM90_REG_R_CONFIG2) & 0xF8) == 0x00
 			   && reg_convrate <= 0x09))) {
 				kind = lm90;
-				name = "lm90";
 			}
 		}
 		else if (man_id == 0x41) { /* Analog Devices */
@@ -355,7 +344,6 @@
 			 && (kind == 0 /* skip detection */
 			  || (reg_config1 & 0x3F) == 0x00)) {
 				kind = adm1032;
-				name = "adm1032";
 			}
 		}
 
@@ -367,6 +355,12 @@
 		}
 	}
 
+	if (kind == lm90) {
+		name = "lm90";
+	} else if (kind == adm1032) {
+		name = "adm1032";
+	}
+
 	/* We can fill in the remaining client fields */
 	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	new_client->id = lm90_id++;
@@ -381,16 +375,16 @@
 	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 @@
 	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 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_lm90_init(void)
diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c
--- a/drivers/i2c/chips/via686a.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/i2c/chips/via686a.c	Sat Apr  3 19:38:41 2004
@@ -32,10 +32,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_CHIP
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
@@ -409,30 +405,24 @@
 	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 +472,10 @@
 {								\
 	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 +486,15 @@
 
 /* 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 +540,10 @@
 {									\
 	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 +552,17 @@
 
 /* 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 +609,10 @@
 {									\
 	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 +620,7 @@
 
 /* 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 +629,7 @@
    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 +718,36 @@
 	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 +830,9 @@
 			    !(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 +893,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static struct pci_device_id via686a_pci_ids[] = {
diff -Nru a/drivers/i2c/chips/w83627hf.c b/drivers/i2c/chips/w83627hf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/chips/w83627hf.c	Sat Apr  3 19:38:57 2004
@@ -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;
+	else {
+		dev_info(&adapter->dev,
+			 "Unsupported chip (dev_id=0x%02X).\n", val);
+		goto ERROR1;
+	}
+
+	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";
+	}
+
+	/* 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 -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c
--- a/drivers/i2c/chips/w83781d.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/i2c/chips/w83781d.c	Sat Apr  3 19:38:40 2004
@@ -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)
@@ -37,10 +36,6 @@
 */
 
 #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>
@@ -248,10 +243,10 @@
 	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 +272,7 @@
 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 +293,7 @@
 #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 +322,7 @@
 { \
         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 +333,7 @@
 { \
 	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 +352,15 @@
 
 #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 +388,7 @@
 { \
 	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 +399,7 @@
 { \
 	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 +410,14 @@
 
 #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 +432,7 @@
 }
 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 +460,7 @@
 	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 +468,7 @@
 { \
 	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 +479,12 @@
 { \
 	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 +492,26 @@
 
 #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 +535,7 @@
 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 +546,7 @@
 #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,62 +607,114 @@
 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]));
+}
+
+/* Note: we save and restore the fan minimum here, because its value is
+   determined in part by the fan divisor.  This follows the principle of
+   least suprise; the user doesn't expect the fan minimum to change just
+   because the divisor changed. */
+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);
+	unsigned long min;
+	u8 reg;
 
-	w83781d_update_client(client);
+	/* Save fan_min */
+	min = FAN_FROM_REG(data->fan_min[0],
+			   DIV_FROM_REG(data->fan_div[0]));
+
+	data->fan_div[0] = DIV_TO_REG(simple_strtoul(buf, NULL, 10),
+				      data->type);
+
+	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);
 
-	return sprintf(buf, "%ld\n",
-		       (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+	/* 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);
+	}
+
+	/* Restore fan_min */
+	data->fan_min[0] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[0]));
+	w83781d_write_value(client, W83781D_REG_FAN_MIN(1), data->fan_min[0]);
+
+	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;
+	unsigned long min;
+	u8 reg;
 
-	val = simple_strtoul(buf, NULL, 10);
-	old = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
-
-	data->fan_div[nr - 1] = DIV_TO_REG(val, data->type);
+	/* Save fan_min */
+	min = FAN_FROM_REG(data->fan_min[1],
+			   DIV_FROM_REG(data->fan_div[1]));
+
+	data->fan_div[1] = DIV_TO_REG(simple_strtoul(buf, NULL, 10),
+				      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);
+	/* Restore fan_min */
+	data->fan_min[1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[1]));
+	w83781d_write_value(client, W83781D_REG_FAN_MIN(2), data->fan_min[1]);
 
-		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);
+	return count;
+}
 
-		if ((data->type != w83781d) && (data->type != as99127f)) {
-			old3 = (old3 & 0xdf) | ((data->fan_div[0] & 0x04) << 3);
-			w83781d_write_value(client, W83781D_REG_VBAT, old3);
-		}
+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);
+	unsigned long min;
+	u8 reg;
+
+	/* Save fan_min */
+	min = FAN_FROM_REG(data->fan_min[2],
+			   DIV_FROM_REG(data->fan_div[2]));
+
+	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);
 	}
 
+	/* Restore fan_min */
+	data->fan_min[2] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[2]));
+	w83781d_write_value(client, W83781D_REG_FAN_MIN(3), data->fan_min[2]);
+
 	return count;
 }
 
@@ -704,11 +723,7 @@
 { \
 	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 +731,14 @@
 
 #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 +746,7 @@
 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 +816,7 @@
 { \
 	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 +827,7 @@
 { \
 	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 +837,18 @@
 
 #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 +905,7 @@
 { \
     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 +913,16 @@
 
 #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]);
@@ -997,7 +997,7 @@
 {
 	int i, val1 = 0, id;
 	int err;
-	const char *client_name;
+	const char *client_name = "";
 	struct w83781d_data *data = i2c_get_clientdata(new_client);
 
 	data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
@@ -1063,8 +1063,6 @@
 		client_name = "w83627hf subclient";
 	else if (kind == as99127f)
 		client_name = "as99127f subclient";
-	else
-		client_name = "unknown subclient?";
 
 	for (i = 0; i <= 1; i++) {
 		/* store all data in w83781d */
@@ -1118,6 +1116,23 @@
 		goto ERROR0;
 	}
 
+	/* Prevent users from forcing a kind for a bus it isn't supposed
+	   to possibly be on */
+	if (is_isa && (kind == as99127f || kind == w83783s)) {
+		dev_err(&adapter->dev,
+			"Cannot force I2C-only chip for ISA address 0x%02x.\n",
+			address);
+		err = -EINVAL;
+		goto ERROR0;
+	}
+	if (!is_isa && kind == w83697hf) {
+		dev_err(&adapter->dev,
+			"Cannot force ISA-only chip for I2C address 0x%02x.\n",
+			address);
+		err = -EINVAL;
+		goto ERROR0;
+	}
+	
 	if (is_isa)
 		if (!request_region(address, W83781D_EXTENT, "w83781d")) {
 			err = -EBUSY;
@@ -1194,10 +1209,8 @@
 		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 +1239,7 @@
 		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;
@@ -1273,11 +1286,6 @@
 		client_name = "as99127f";
 	} else if (kind == w83697hf) {
 		client_name = "w83697hf";
-	} 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 */
@@ -1632,7 +1640,11 @@
 		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 +1657,9 @@
 			    | 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 +1709,13 @@
 		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 +1723,7 @@
 			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 +1772,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init
diff -Nru a/drivers/i2c/chips/w83l785ts.c b/drivers/i2c/chips/w83l785ts.c
--- a/drivers/i2c/chips/w83l785ts.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/i2c/chips/w83l785ts.c	Sat Apr  3 19:38:42 2004
@@ -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
@@ -28,10 +31,6 @@
  */
 
 #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>
@@ -86,7 +85,7 @@
 	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 +126,18 @@
 
 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
@@ -164,7 +159,6 @@
 	struct i2c_client *new_client;
 	struct w83l785ts_data *data;
 	int err = 0;
-	const char *name = "";
 
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -225,7 +219,6 @@
 		if (man_id == 0x5CA3) { /* Winbond */
 			if (chip_id == 0x70) { /* W83L785TS-S */
 				kind = w83l785ts;			
-				name = "w83l785ts";
 			}
 		}
 	
@@ -238,7 +231,7 @@
 	}
 
 	/* We can fill in the remaining client fields. */
-	strlcpy(new_client->name, name, I2C_NAME_SIZE);
+	strlcpy(new_client->name, "w83l785ts", I2C_NAME_SIZE);
 	new_client->id = w83l785ts_id++;
 	data->valid = 0;
 	init_MUTEX(&data->update_lock);
@@ -256,8 +249,8 @@
 	 */
 
 	/* 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 +294,9 @@
 	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 +315,8 @@
 	}
 
 	up(&data->update_lock);
+
+	return data;
 }
 
 static int __init sensors_w83l785ts_init(void)
diff -Nru a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
--- a/drivers/i2c/i2c-core.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/i2c/i2c-core.c	Sat Apr  3 19:38:41 2004
@@ -22,10 +22,6 @@
    SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com>                */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_CORE
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -175,7 +171,7 @@
 		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 +433,11 @@
 
 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 +617,7 @@
 	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 -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
--- a/drivers/i2c/i2c-dev.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/i2c/i2c-dev.c	Sat Apr  3 19:38:54 2004
@@ -30,10 +30,6 @@
    <pmhahn@titan.lahn.de> */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_CORE
-#define DEBUG	1
-#endif
-
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -72,24 +68,18 @@
 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 +87,16 @@
 	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 +115,13 @@
 }
 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 +185,7 @@
 	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 +306,7 @@
 		    (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 +315,7 @@
 		   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 +334,7 @@
 					      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 +437,7 @@
 	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 +457,7 @@
 	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 -Nru a/drivers/i2c/i2c-sensor.c b/drivers/i2c/i2c-sensor.c
--- a/drivers/i2c/i2c-sensor.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/i2c/i2c-sensor.c	Sat Apr  3 19:38:43 2004
@@ -20,10 +20,6 @@
 */
 
 #include <linux/config.h>
-#ifdef CONFIG_I2C_DEBUG_CORE
-#define DEBUG	1
-#endif
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
diff -Nru a/drivers/ide/Kconfig b/drivers/ide/Kconfig
--- a/drivers/ide/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/Kconfig	Sat Apr  3 19:38:43 2004
@@ -559,6 +559,16 @@
 	  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
@@ -1103,9 +1113,6 @@
 
 config IDEDMA_AUTO
 	def_bool IDEDMA_PCI_AUTO || BLK_DEV_IDEDMA_PMAC_AUTO || IDEDMA_ICS_AUTO
-
-config DMA_NONPCI
-	def_bool BLK_DEV_TIVO
 
 endif
 
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/ide-cd.c	Sat Apr  3 19:38:43 2004
@@ -554,53 +554,6 @@
 	(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 @@
 	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: */
@@ -2419,7 +2372,7 @@
 
 	/* Now try to get the total cdrom capacity. */
 	stat = cdrom_get_last_written(cdi, &last_written);
-	if (!stat && last_written) {
+	if (!stat && (last_written > toc->capacity)) {
 		toc->capacity = last_written;
 		set_capacity(drive->disk, toc->capacity * sectors_per_frame);
 	}
@@ -2930,7 +2883,10 @@
 		devinfo->mask |= CDC_MRW;
 	if (!CDROM_CONFIG_FLAGS(drive)->mrw_w)
 		devinfo->mask |= CDC_MRW_W;
+	if (!CDROM_CONFIG_FLAGS(drive)->ram)
+		devinfo->mask |= CDC_RAM;
 
+	devinfo->disk = drive->disk;
 	return register_cdrom(devinfo);
 }
 
@@ -2965,7 +2921,7 @@
 	struct cdrom_info *info = drive->driver_data;
 	struct cdrom_device_info *cdi = &info->devinfo;
 	struct atapi_capabilities_page cap;
-	int nslots = 1, mrw_write = 0;
+	int nslots = 1, mrw_write = 0, ram_write = 0;
 
 	if (drive->media == ide_optical) {
 		CDROM_CONFIG_FLAGS(drive)->mo_drive = 1;
@@ -3001,6 +2957,9 @@
 			CDROM_CONFIG_FLAGS(drive)->ram = 1;
 		}
 	}
+	if (!cdrom_is_random_writable(cdi, &ram_write))
+		if (ram_write)
+			CDROM_CONFIG_FLAGS(drive)->ram = 1;
 
 	if (cap.lock == 0)
 		CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1;
@@ -3411,7 +3370,7 @@
 	.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,
@@ -3551,6 +3510,7 @@
 
 	cdrom_read_toc(drive, &sense);
 	g->fops = &idecd_ops;
+	g->flags |= GENHD_FL_REMOVABLE;
 	add_disk(g);
 	return 0;
 failed:
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/ide-disk.c	Sat Apr  3 19:38:43 2004
@@ -569,28 +569,37 @@
 }
 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 
 	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 @@
 	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 @@
 	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 @@
 			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 @@
 			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 @@
 			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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 							  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 @@
 			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 @@
 		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 @@
 		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 -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/ide-dma.c	Sat Apr  3 19:38:43 2004
@@ -883,16 +883,6 @@
 	return 1;
 }
 
-int ide_release_mmio_dma (ide_hwif_t *hwif)
-{
-	if ((hwif->dma_extra) && (hwif->channel == 0))
-		release_mem_region((hwif->dma_base + 16), hwif->dma_extra);
-	release_mem_region(hwif->dma_base, 8);
-	if (hwif->dma_base2)
-		release_mem_region(hwif->dma_base, 8);
-	return 1;
-}
-
 int ide_release_iomio_dma (ide_hwif_t *hwif)
 {
 	if ((hwif->dma_extra) && (hwif->channel == 0))
@@ -914,8 +904,6 @@
 		return 1;
 
 	ide_release_dma_engine(hwif);
-	if (hwif->mmio == 1)
-		return ide_release_mmio_dma(hwif);
 	return ide_release_iomio_dma(hwif);
 }
 
@@ -939,38 +927,6 @@
 	return 1;
 }
 
-int ide_mmio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
-{
-	printk(KERN_INFO "    %s: MMIO-DMA at 0x%08lx-0x%08lx",
-		hwif->name, base, base + ports - 1);
-	if (!request_mem_region(base, ports, hwif->name))
-		goto fail;
-	hwif->dma_base = base;
-	if ((hwif->cds->extra) && (hwif->channel == 0)) {
-		if (!request_region(base+16, hwif->cds->extra, hwif->cds->name))
-			goto release_mem;
-		hwif->dma_extra = hwif->cds->extra;
-	}
-	
-	if(hwif->mate)
-		hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
-	else
-		hwif->dma_master = base;
-	if (hwif->dma_base2) {
-		if (!request_mem_region(hwif->dma_base2, ports, hwif->name))
-			goto release_io;
-	}
-	return 0;
-
-release_mem:
-	release_mem_region(base, ports);
-release_io:
-	release_region(base+16, hwif->cds->extra);
-fail:
-	printk(" -- Error, MMIO ports already in use.\n");
-	return 1;
-}
-
 int ide_mapped_mmio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports)
 {
 	printk(KERN_INFO "    %s: MMIO-DMA ", hwif->name);
@@ -1022,8 +978,7 @@
 {
 	if (hwif->mmio == 2)
 		return ide_mapped_mmio_dma(hwif, base,ports);
-	if (hwif->mmio == 1)
-		return ide_mmio_dma(hwif, base, ports);
+	BUG_ON(hwif->mmio == 1);
 	return ide_iomio_dma(hwif, base, ports);
 }
 
diff -Nru a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
--- a/drivers/ide/ide-io.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/ide/ide-io.c	Sat Apr  3 19:38:55 2004
@@ -197,7 +197,7 @@
 			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 @@
 			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 -Nru a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
--- a/drivers/ide/ide-iops.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/ide-iops.c	Sat Apr  3 19:38:42 2004
@@ -829,10 +829,10 @@
 //	while (HWGROUP(drive)->busy)
 //		ide_delay_50ms();
 
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
+#ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->ide_dma_check)	 /* check if host supports DMA */
 		hwif->ide_dma_host_off(drive);
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+#endif
 
 	/*
 	 * Don't use ide_wait_cmd here - it will
@@ -906,14 +906,12 @@
 	drive->id->dma_mword &= ~0x0F00;
 	drive->id->dma_1word &= ~0x0F00;
 
-#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)
-	if (speed >= XFER_SW_DMA_0) {
+#ifdef CONFIG_BLK_DEV_IDEDMA
+	if (speed >= XFER_SW_DMA_0)
 		hwif->ide_dma_host_on(drive);
-	} else {
-		if (hwif->ide_dma_check) /* check if host supports DMA */
-			hwif->ide_dma_off_quietly(drive);
-	}
-#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */
+	else if (hwif->ide_dma_check)	/* check if host supports DMA */
+		hwif->ide_dma_off_quietly(drive);
+#endif
 
 	switch(speed) {
 		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;
diff -Nru a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
--- a/drivers/ide/ide-lib.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/ide/ide-lib.c	Sat Apr  3 19:38:56 2004
@@ -447,3 +447,55 @@
 
 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 -Nru a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c
--- a/drivers/ide/ide-pnp.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/ide/ide-pnp.c	Sat Apr  3 19:38:44 2004
@@ -64,7 +64,6 @@
 	if (index != -1) {
 	    	printk(KERN_INFO "ide%d: generic PnP IDE interface\n", index);
 		pnp_set_drvdata(dev,hwif);
-		hwif->pnp_dev = dev;
 		return 0;
 	}
 
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/ide/ide-probe.c	Sat Apr  3 19:38:44 2004
@@ -138,9 +138,6 @@
 	local_irq_enable();
 	ide_fix_driveid(id);
 
-	if (!drive->forced_lun)
-		drive->last_lun = id->last_lun & 0x7;
-
 #if defined (CONFIG_SCSI_EATA_DMA) || defined (CONFIG_SCSI_EATA_PIO) || defined (CONFIG_SCSI_EATA)
 	/*
 	 * EATA SCSI controllers do a hardware ATA emulation:
@@ -847,7 +844,6 @@
 int hwif_init (ide_hwif_t *hwif);
 int probe_hwif_init (ide_hwif_t *hwif)
 {
-	hwif->initializing = 1;
 	probe_hwif(hwif);
 	hwif_init(hwif);
 
@@ -863,7 +859,6 @@
 			}
 		}
 	}
-	hwif->initializing = 0;
 	return 0;
 }
 
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/ide/ide-taskfile.c	Sat Apr  3 19:38:40 2004
@@ -101,7 +101,8 @@
 		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 @@
 	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,336 +991,11 @@
 
 #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().
- */
-void ide_init_drive_taskfile (struct request *rq)
-{
-	memset(rq, 0, sizeof(*rq));
-	rq->flags = REQ_DRIVE_TASKFILE;
-}
-
-EXPORT_SYMBOL(ide_init_drive_taskfile);
-
 int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf)
 {
 	struct request rq;
 
-	ide_init_drive_taskfile(&rq);
+	memset(&rq, 0, sizeof(rq));
 	rq.flags = REQ_DRIVE_TASKFILE;
 	rq.buffer = buf;
 
@@ -1331,7 +1007,7 @@
 	 */
 	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 +1015,6 @@
 		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 +1117,9 @@
 #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 -Nru a/drivers/ide/ide-tcq.c b/drivers/ide/ide-tcq.c
--- a/drivers/ide/ide-tcq.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/ide/ide-tcq.c	Sat Apr  3 19:38:56 2004
@@ -483,7 +483,7 @@
 
 	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 @@
 	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 @@
 	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 @@
 	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 -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/ide.c	Sat Apr  3 19:38:42 2004
@@ -482,23 +482,14 @@
 static struct resource* hwif_request_region(ide_hwif_t *hwif,
 					    unsigned long addr, int num)
 {
-	struct resource *res;
-
-	if (hwif->mmio)
-		res = request_mem_region(addr, num, hwif->name);
-	else
-		res = request_region(addr, num, hwif->name);
+	struct resource *res = request_region(addr, num, hwif->name);
 
 	if (!res)
-		printk(KERN_ERR "%s: %s resource 0x%lX-0x%lX not free.\n",
-				hwif->name, hwif->mmio ? "MMIO" : "I/O",
-				addr, addr+num-1);
+		printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
+				hwif->name, addr, addr+num-1);
 	return res;
 }
 
-#define hwif_release_region(addr, num) \
-	((hwif->mmio) ? release_mem_region((addr),(num)) : release_region((addr),(num)))
-
 /**
  *	ide_hwif_request_regions - request resources for IDE
  *	@hwif: interface to use
@@ -515,14 +506,10 @@
 
 	if (hwif->mmio == 2)
 		return 0;
+	BUG_ON(hwif->mmio == 1);
 	addr = hwif->io_ports[IDE_CONTROL_OFFSET];
 	if (addr && !hwif_request_region(hwif, addr, 1))
 		goto control_region_busy;
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	addr = hwif->io_ports[IDE_IRQ_OFFSET];
-	if (addr && !hwif_request_region(hwif, addr, 1))
-		goto irq_region_busy;
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
 	hwif->straight8 = 0;
 	addr = hwif->io_ports[IDE_DATA_OFFSET];
 	if ((addr | 7) == hwif->io_ports[IDE_STATUS_OFFSET]) {
@@ -535,22 +522,16 @@
 		addr = hwif->io_ports[i];
 		if (!hwif_request_region(hwif, addr, 1)) {
 			while (--i)
-				hwif_release_region(addr, 1);
+				release_region(addr, 1);
 			goto data_region_busy;
 		}
 	}
 	return 0;
 
 data_region_busy:
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	addr = hwif->io_ports[IDE_IRQ_OFFSET];
-	if (addr)
-		hwif_release_region(addr, 1);
-irq_region_busy:
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
 	addr = hwif->io_ports[IDE_CONTROL_OFFSET];
 	if (addr)
-		hwif_release_region(addr, 1);
+		release_region(addr, 1);
 control_region_busy:
 	/* If any errors are return, we drop the hwif interface. */
 	return -EBUSY;
@@ -576,21 +557,14 @@
 	if (hwif->mmio == 2)
 		return;
 	if (hwif->io_ports[IDE_CONTROL_OFFSET])
-		hwif_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
-#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)
-	if (hwif->io_ports[IDE_IRQ_OFFSET])
-		hwif_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);
-#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */
-
+		release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);
 	if (hwif->straight8) {
-		hwif_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
+		release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);
 		return;
 	}
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		if (hwif->io_ports[i]) {
-			hwif_release_region(hwif->io_ports[i], 1);
-		}
-	}
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++)
+		if (hwif->io_ports[i])
+			release_region(hwif->io_ports[i], 1);
 }
 
 EXPORT_SYMBOL(ide_hwif_release_regions);
@@ -763,7 +737,6 @@
 	unregister_blkdev(hwif->major, hwif->name);
 	spin_lock_irq(&ide_lock);
 
-#if !defined(CONFIG_DMA_NONPCI)
 	if (hwif->dma_base) {
 		(void) ide_release_dma(hwif);
 
@@ -775,7 +748,7 @@
 		hwif->dma_vendor3 = 0;
 		hwif->dma_prdtable = 0;
 	}
-#endif /* !(CONFIG_DMA_NONPCI) */
+
 	old_hwif			= *hwif;
 	init_hwif_data(index);	/* restore hwif data to pristine status */
 	hwif->hwgroup			= old_hwif.hwgroup;
@@ -869,7 +842,6 @@
 #ifndef CONFIG_BLK_DEV_IDECS
 	hwif->irq			= old_hwif.irq;
 #endif /* CONFIG_BLK_DEV_IDECS */
-	hwif->initializing		= old_hwif.initializing;
 
 	hwif->dma_base			= old_hwif.dma_base;
 	hwif->dma_master		= old_hwif.dma_master;
@@ -1798,9 +1770,7 @@
 	if (strncmp(s,"hd",2) == 0 && s[2] == '=')	/* hd= is for hd.c   */
 		return 0;				/* driver and not us */
 
-	if (strncmp(s,"ide",3) &&
-	    strncmp(s,"idebus",6) &&
-	    strncmp(s,"hd",2))		/* hdx= & hdxlun= */
+	if (strncmp(s,"ide",3) && strncmp(s,"idebus",6) && strncmp(s,"hd",2))
 		return 0;
 
 	printk(KERN_INFO "ide_setup: %s", s);
@@ -1847,19 +1817,6 @@
 			strlcpy(drive->driver_req, s + 4, sizeof(drive->driver_req));
 			goto done;
 		}
-		/*
-		 * Look for last lun option:  "hdxlun="
-		 */
-		if (s[3] == 'l' && s[4] == 'u' && s[5] == 'n') {
-			if (match_parm(&s[6], NULL, vals, 1) != 1)
-				goto bad_option;
-			if (vals[0] >= 0 && vals[0] <= 7) {
-				drive->last_lun = vals[0];
-				drive->forced_lun = 1;
-			} else
-				printk(" -- BAD LAST LUN! Expected value from 0 to 7");
-			goto done;
-		}
 		switch (match_parm(&s[3], hd_words, vals, 3)) {
 			case -1: /* "none" */
 			case -2: /* "noprobe" */
@@ -2466,10 +2423,8 @@
 
 	for (index = 0; index < MAX_HWIFS; ++index) {
 		ide_unregister(index);
-#if !defined(CONFIG_DMA_NONPCI)
 		if (ide_hwifs[index].dma_base)
 			(void) ide_release_dma(&ide_hwifs[index]);
-#endif /* !(CONFIG_DMA_NONPCI) */
 	}
 
 #ifdef CONFIG_PROC_FS
diff -Nru a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
--- a/drivers/ide/legacy/macide.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/ide/legacy/macide.c	Sat Apr  3 19:38:40 2004
@@ -94,6 +94,7 @@
 void macide_init(void)
 {
 	hw_regs_t hw;
+	ide_hwif_t *hwif;
 	int index = -1;
 
 	switch (macintosh_config->ide_type) {
@@ -102,21 +103,21 @@
 				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 @@
 	}
 
         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 -Nru a/drivers/ide/legacy/pdc4030.c b/drivers/ide/legacy/pdc4030.c
--- a/drivers/ide/legacy/pdc4030.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/legacy/pdc4030.c	Sat Apr  3 19:38:43 2004
@@ -814,11 +814,10 @@
 
 	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 -Nru a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
--- a/drivers/ide/pci/Makefile	Sat Apr  3 19:38:41 2004
+++ b/drivers/ide/pci/Makefile	Sat Apr  3 19:38:41 2004
@@ -3,6 +3,7 @@
 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 -Nru a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
--- a/drivers/ide/pci/aec62xx.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/ide/pci/aec62xx.c	Sat Apr  3 19:38:55 2004
@@ -539,6 +539,7 @@
 	{ PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_ATP865R,  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, aec62xx_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "AEC62xx IDE",
diff -Nru a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
--- a/drivers/ide/pci/alim15x3.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/pci/alim15x3.c	Sat Apr  3 19:38:42 2004
@@ -880,6 +880,7 @@
 	{ PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, alim15x3_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "ALI15x3 IDE",
diff -Nru a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
--- a/drivers/ide/pci/amd74xx.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/ide/pci/amd74xx.c	Sat Apr  3 19:38:56 2004
@@ -467,6 +467,7 @@
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "AMD IDE",
diff -Nru a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/ide/pci/atiixp.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,513 @@
+/*
+ *  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, },
+};
+MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
+
+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 -Nru a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
--- a/drivers/ide/pci/cmd64x.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/ide/pci/cmd64x.c	Sat Apr  3 19:38:55 2004
@@ -760,6 +760,7 @@
 	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, cmd64x_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "CMD64x IDE",
diff -Nru a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
--- a/drivers/ide/pci/cs5520.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/ide/pci/cs5520.c	Sat Apr  3 19:38:41 2004
@@ -299,6 +299,7 @@
 	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, cs5520_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "CyrixIDE",
diff -Nru a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
--- a/drivers/ide/pci/cs5530.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/pci/cs5530.c	Sat Apr  3 19:38:42 2004
@@ -417,6 +417,7 @@
 	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, cs5530_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "CS5530 IDE",
diff -Nru a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
--- a/drivers/ide/pci/cy82c693.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/ide/pci/cy82c693.c	Sat Apr  3 19:38:41 2004
@@ -441,6 +441,7 @@
 	{ PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, cy82c693_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "Cypress IDE",
diff -Nru a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
--- a/drivers/ide/pci/generic.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/pci/generic.c	Sat Apr  3 19:38:43 2004
@@ -134,6 +134,7 @@
 	{ PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8237_SATA,	   PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "PCI IDE",
diff -Nru a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
--- a/drivers/ide/pci/hpt34x.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/pci/hpt34x.c	Sat Apr  3 19:38:42 2004
@@ -336,6 +336,7 @@
 	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, hpt34x_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "HPT34x IDE",
diff -Nru a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
--- a/drivers/ide/pci/hpt366.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/ide/pci/hpt366.c	Sat Apr  3 19:38:44 2004
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/ide/pci/hpt366.c		Version 0.34	Sept 17, 2002
  *
- * Copyright (C) 1999-2002		Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
  *
  * Thanks to HighPoint Technologies for their assistance, and hardware.
@@ -641,6 +641,31 @@
 	return __ide_dma_lostirq(drive);
 }
 
+/* returns 1 if DMA IRQ issued, 0 otherwise */
+static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	u16 bfifo		= 0;
+	u8 reginfo		= hwif->channel ? 0x56 : 0x52;
+	u8 dma_stat;
+
+	pci_read_config_word(hwif->pci_dev, reginfo, &bfifo);
+	if (bfifo & 0x1FF) {
+//		printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+		return 0;
+	}
+
+	dma_stat = hwif->INB(hwif->dma_status);
+	/* return 1 if INTR asserted */
+	if ((dma_stat & 4) == 4)
+		return 1;
+
+	if (!drive->waiting_for_dma)
+		printk(KERN_WARNING "%s: (%s) called while not waiting\n",
+				drive->name, __FUNCTION__);
+	return 0;
+}
+
 static int hpt374_ide_dma_end (ide_drive_t *drive)
 {
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
@@ -796,7 +821,7 @@
 	 */
 	pci_read_config_word(dev, 0x78, &freq);
 	freq &= 0x1FF;
-	if (freq < 0x9c) {
+	if (freq < 0xa0) {
 		pll = F_LOW_PCI_33;
 		if (hpt_minimum_revision(dev,8))
 			pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
@@ -872,7 +897,7 @@
 						       pll & ~0x100);
 				pci_write_config_byte(dev, 0x5b, 0x21);
 				if (hpt_minimum_revision(dev,8))
-					return -EOPNOTSUPP;
+					pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
 				else if (hpt_minimum_revision(dev,5))
 					pci_set_drvdata(dev, (void *) fifty_base_hpt372);
 				else if (hpt_minimum_revision(dev,4))
@@ -1069,11 +1094,13 @@
 		hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
 	hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
 
-	if (hpt_minimum_revision(dev,8))
+	if (hpt_minimum_revision(dev,8)) {
+		hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
 		hwif->ide_dma_end = &hpt374_ide_dma_end;
-	else if (hpt_minimum_revision(dev,5))
+	} else if (hpt_minimum_revision(dev,5)) {
+		hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
 		hwif->ide_dma_end = &hpt374_ide_dma_end;
-	else if (hpt_minimum_revision(dev,3)) {
+	} else if (hpt_minimum_revision(dev,3)) {
 		hwif->ide_dma_begin = &hpt370_ide_dma_begin;
 		hwif->ide_dma_end = &hpt370_ide_dma_end;
 		hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
@@ -1228,6 +1255,7 @@
 	{ PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, hpt366_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "HPT366 IDE",
diff -Nru a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
--- a/drivers/ide/pci/it8172.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/ide/pci/it8172.c	Sat Apr  3 19:38:55 2004
@@ -300,6 +300,7 @@
 	{ PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, it8172_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "IT8172IDE",
diff -Nru a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
--- a/drivers/ide/pci/ns87415.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/pci/ns87415.c	Sat Apr  3 19:38:43 2004
@@ -230,6 +230,7 @@
 	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "NS87415IDE",
diff -Nru a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
--- a/drivers/ide/pci/opti621.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/pci/opti621.c	Sat Apr  3 19:38:42 2004
@@ -367,6 +367,7 @@
 	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, opti621_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "Opti621 IDE",
diff -Nru a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
--- a/drivers/ide/pci/pdc202xx_new.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/ide/pci/pdc202xx_new.c	Sat Apr  3 19:38:54 2004
@@ -140,108 +140,6 @@
 	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 @@
  * 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 @@
 {
 	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);
 	}
@@ -487,7 +339,6 @@
 	 */
 	if (hwif->present) {
 		u16 hunit = 0;
-		hwif->initializing = 1;
 		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
 			ide_drive_t *hdrive = &hwif->drives[hunit];
 			if (hdrive->present) {
@@ -497,11 +348,9 @@
 					hwif->tuneproc(hdrive, 5);
 			}
 		}
-		hwif->initializing = 0;
 	}
 	if (mate->present) {
 		u16 munit = 0;
-		mate->initializing = 1;
 		for (munit = 0; munit < MAX_DRIVES; ++munit) {
 			ide_drive_t *mdrive = &mate->drives[munit];
 			if (mdrive->present) {
@@ -511,7 +360,6 @@
 					mate->tuneproc(mdrive, 5);
 			}
 		}
-		mate->initializing = 0;
 	}
 #else
 	hwif->tuneproc(drive, 5);
@@ -590,10 +438,7 @@
 	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;
@@ -685,6 +530,7 @@
 	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, pdc202new_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "Promise IDE",
diff -Nru a/drivers/ide/pci/pdc202xx_new.h b/drivers/ide/pci/pdc202xx_new.h
--- a/drivers/ide/pci/pdc202xx_new.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/ide/pci/pdc202xx_new.h	Sat Apr  3 19:38:41 2004
@@ -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",
@@ -25,116 +16,6 @@
 	"QUANTUM FIREBALLP LM20.5",
 	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 {						\
diff -Nru a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
--- a/drivers/ide/pci/pdc202xx_old.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/ide/pci/pdc202xx_old.c	Sat Apr  3 19:38:56 2004
@@ -618,7 +618,6 @@
 	 */
 	if (hwif->present) {
 		u16 hunit = 0;
-		hwif->initializing = 1;
 		for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
 			ide_drive_t *hdrive = &hwif->drives[hunit];
 			if (hdrive->present) {
@@ -628,11 +627,9 @@
 					hwif->tuneproc(hdrive, 5);
 			}
 		}
-		hwif->initializing = 0;
 	}
 	if (mate->present) {
 		u16 munit = 0;
-		mate->initializing = 1;
 		for (munit = 0; munit < MAX_DRIVES; ++munit) {
 			ide_drive_t *mdrive = &mate->drives[munit];
 			if (mdrive->present) {
@@ -642,7 +639,6 @@
 					mate->tuneproc(mdrive, 5);
 			}
 		}
-		mate->initializing = 0;
 	}
 #else
 	hwif->tuneproc(drive, 5);
@@ -902,6 +898,7 @@
 	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, pdc202xx_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "Promise Old IDE",
diff -Nru a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
--- a/drivers/ide/pci/piix.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/ide/pci/piix.c	Sat Apr  3 19:38:41 2004
@@ -807,6 +807,7 @@
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 20},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "PIIX IDE",
@@ -814,7 +815,7 @@
 	.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 -Nru a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
--- a/drivers/ide/pci/rz1000.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/pci/rz1000.c	Sat Apr  3 19:38:42 2004
@@ -68,6 +68,7 @@
 	{ PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, rz1000_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "RZ1000 IDE",
diff -Nru a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
--- a/drivers/ide/pci/sc1200.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/ide/pci/sc1200.c	Sat Apr  3 19:38:44 2004
@@ -558,6 +558,7 @@
 	{ PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "SC1200 IDE",
diff -Nru a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
--- a/drivers/ide/pci/serverworks.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/ide/pci/serverworks.c	Sat Apr  3 19:38:41 2004
@@ -809,6 +809,7 @@
 	{ PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, svwks_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "Serverworks IDE",
diff -Nru a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
--- a/drivers/ide/pci/sgiioc4.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/pci/sgiioc4.c	Sat Apr  3 19:38:43 2004
@@ -790,6 +790,7 @@
 	 PCI_ANY_ID, 0x0b4000, 0xFFFFFF, 0},
 	{0}
 };
+MODULE_DEVICE_TABLE(pci, sgiioc4_pci_tbl);
 
 static struct pci_driver driver = {
 	.name = "SGI-IOC4 IDE",
diff -Nru a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
--- a/drivers/ide/pci/siimage.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/pci/siimage.c	Sat Apr  3 19:38:42 2004
@@ -1196,6 +1196,7 @@
 	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, siimage_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "SiI IDE",
diff -Nru a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
--- a/drivers/ide/pci/sis5513.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ide/pci/sis5513.c	Sat Apr  3 19:38:43 2004
@@ -957,6 +957,7 @@
 	{ PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5513, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, sis5513_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "SIS IDE",
diff -Nru a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
--- a/drivers/ide/pci/sl82c105.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/pci/sl82c105.c	Sat Apr  3 19:38:42 2004
@@ -494,6 +494,7 @@
 	{ PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "W82C105 IDE",
diff -Nru a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
--- a/drivers/ide/pci/slc90e66.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/ide/pci/slc90e66.c	Sat Apr  3 19:38:54 2004
@@ -377,6 +377,7 @@
 	{ PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "SLC90e66 IDE",
diff -Nru a/drivers/ide/pci/triflex.h b/drivers/ide/pci/triflex.h
--- a/drivers/ide/pci/triflex.h	Sat Apr  3 19:38:54 2004
+++ b/drivers/ide/pci/triflex.h	Sat Apr  3 19:38:54 2004
@@ -37,5 +37,6 @@
 		PCI_ANY_ID, 0, 0, 0 },
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, triflex_pci_tbl);
 
 #endif /* TRIFLEX_H */
diff -Nru a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
--- a/drivers/ide/pci/trm290.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ide/pci/trm290.c	Sat Apr  3 19:38:42 2004
@@ -280,7 +280,7 @@
 static int trm290_ide_dma_end (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	u16 status = 0;;
+	u16 status = 0;
 
 	drive->waiting_for_dma = 0;
 	/* purge DMA mappings */
@@ -408,6 +408,7 @@
 	{ PCI_VENDOR_ID_TEKRAM, PCI_DEVICE_ID_TEKRAM_DC290, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, trm290_pci_tbl);
 
 static struct pci_driver driver = {
 	.name		= "TRM290 IDE",
diff -Nru a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
--- a/drivers/ide/pci/via82cxxx.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/ide/pci/via82cxxx.c	Sat Apr  3 19:38:40 2004
@@ -621,6 +621,7 @@
 	{ PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
 	{ 0, },
 };
+MODULE_DEVICE_TABLE(pci, via_pci_tbl);
 
 static struct pci_driver driver = {
 	.name 		= "VIA IDE",
diff -Nru a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c
--- a/drivers/ieee1394/amdtp.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/ieee1394/amdtp.c	Sat Apr  3 19:38:44 2004
@@ -1266,7 +1266,6 @@
 {
 	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 -Nru a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
--- a/drivers/ieee1394/dma.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/ieee1394/dma.c	Sat Apr  3 19:38:43 2004
@@ -168,7 +168,7 @@
 	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 @@
 	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 -Nru a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h
--- a/drivers/ieee1394/dma.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/ieee1394/dma.h	Sat Apr  3 19:38:55 2004
@@ -60,8 +60,10 @@
 /* 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 -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
--- a/drivers/ieee1394/dv1394.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/ieee1394/dv1394.c	Sat Apr  3 19:38:54 2004
@@ -553,7 +553,7 @@
 	*(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 @@
 			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 @@
 
 	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 -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
--- a/drivers/ieee1394/ieee1394_core.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/ieee1394/ieee1394_core.c	Sat Apr  3 19:38:42 2004
@@ -1201,7 +1201,8 @@
 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 -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
--- a/drivers/ieee1394/ohci1394.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/ieee1394/ohci1394.c	Sat Apr  3 19:38:55 2004
@@ -1732,7 +1732,7 @@
 		/* OK, the block is finished... */
 		
 		/* sync our view of the block */
-		dma_region_sync(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
+		dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride);
 		
 		/* reset the DMA descriptor */
 		im->status = recv->buf_stride;
@@ -1789,7 +1789,7 @@
 		}
 
 		/* sync our view of the buffer */
-		dma_region_sync(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
+		dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride);
 			
 		/* record the per-packet info */
 		{
@@ -2016,7 +2016,7 @@
 	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 -Nru a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
--- a/drivers/ieee1394/raw1394.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/ieee1394/raw1394.c	Sat Apr  3 19:38:40 2004
@@ -2746,9 +2746,9 @@
 
 	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 -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/ieee1394/sbp2.c	Sat Apr  3 19:38:41 2004
@@ -1948,12 +1948,12 @@
 	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 @@
 			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 @@
 	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 @@
 		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 @@
 		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 -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
--- a/drivers/ieee1394/video1394.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/ieee1394/video1394.c	Sat Apr  3 19:38:41 2004
@@ -1457,7 +1457,6 @@
 
 	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 -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/input/evdev.c	Sat Apr  3 19:38:54 2004
@@ -209,7 +209,7 @@
 	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 @@
 			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 -Nru a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
--- a/drivers/input/gameport/ns558.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/input/gameport/ns558.c	Sat Apr  3 19:38:55 2004
@@ -77,7 +77,7 @@
  * No one should be using this address.
  */
 
-	if (check_region(io, 1))
+	if (!request_region(io, 1, "ns558-isa"))
 		return;
 
 /*
@@ -89,7 +89,8 @@
 	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 @@
 
 	if (u == v) {
 		outb(c, io);
-		return;
+		i = 0;
+		goto out;
 	}
 	wait_ms(3);
 /*
@@ -110,7 +112,8 @@
 	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 @@
 
 	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 @@
 			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 @@
 	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 @@
 	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 @@
 #endif
 			case NS558_ISA:
 				release_region(port->gameport.io & ~(port->size - 1), port->size);
+				kfree(port);
 				break;
 		
 			default:
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/input/input.c	Sat Apr  3 19:38:43 2004
@@ -727,6 +727,8 @@
 	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 @@
 		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 @@
 		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 -Nru a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
--- a/drivers/input/joystick/amijoy.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/input/joystick/amijoy.c	Sat Apr  3 19:38:45 2004
@@ -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" };
@@ -100,17 +106,6 @@
 	if (!--(*used))
 		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)
 {
diff -Nru a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
--- a/drivers/input/joystick/analog.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/input/joystick/analog.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 #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 @@
 	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])) {
@@ -741,24 +745,6 @@
 	.connect =	analog_connect,
 	.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)
 {
diff -Nru a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
--- a/drivers/input/joystick/db9.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/input/joystick/db9.c	Sat Apr  3 19:38:42 2004
@@ -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_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 @@
 #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 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 @@
 
 	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 @@
 	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 -Nru a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
--- a/drivers/input/joystick/gamecon.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/input/joystick/gamecon.c	Sat Apr  3 19:38:56 2004
@@ -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_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 @@
 
 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 @@
 #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 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 @@
 	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 @@
 	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 @@
 	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 -Nru a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
--- a/drivers/input/joystick/gf2k.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/input/joystick/gf2k.c	Sat Apr  3 19:38:45 2004
@@ -109,7 +109,7 @@
 	local_irq_save(flags);
 
 	gameport_trigger(gameport);
-	v = gameport_read(gameport);;
+	v = gameport_read(gameport);
 
 	while (t > 0 && i < length) {
 		t--; u = v;
diff -Nru a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
--- a/drivers/input/joystick/iforce/iforce-usb.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/input/joystick/iforce/iforce-usb.c	Sat Apr  3 19:38:55 2004
@@ -135,7 +135,7 @@
 	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 -Nru a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
--- a/drivers/input/joystick/turbografx.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/input/joystick/turbografx.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 #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 @@
  * 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 @@
 	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 @@
 
 	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 @@
 	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 -Nru a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
--- a/drivers/input/keyboard/Kconfig	Sat Apr  3 19:38:56 2004
+++ b/drivers/input/keyboard/Kconfig	Sat Apr  3 19:38:56 2004
@@ -17,6 +17,7 @@
 	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
@@ -39,6 +40,19 @@
 
 	  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"
diff -Nru a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
--- a/drivers/input/keyboard/Makefile	Sat Apr  3 19:38:57 2004
+++ b/drivers/input/keyboard/Makefile	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/input/keyboard/atkbd.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 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 @@
 #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 @@
 #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 @@
 	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 @@
 {
 	struct atkbd *atkbd = serio->private;
 	unsigned int code = data;
+	int scroll = 0, click = -1;
 	int value;
 
 #ifdef ATKBD_DEBUG
@@ -202,7 +228,7 @@
 		atkbd->resend = 1;
 		goto out;
 	}
-	
+
 	if (!flags && data == ATKBD_RET_ACK)
 		atkbd->resend = 0;
 #endif
@@ -276,7 +302,7 @@
 		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 @@
 			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 @@
 			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 @@
 	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 @@
 			atkbd->cmdcnt = 0;
 			break;
 		}
-	
+
 		udelay(1);
 	}
 
@@ -420,7 +468,7 @@
 			         | (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 @@
  */
 
 	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 @@
 		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 @@
 
 	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 @@
 			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 @@
 			kfree(atkbd);
 			return;
 		}
-		
+
 		atkbd->set = atkbd_set_3(atkbd);
 		atkbd_enable(atkbd);
 
@@ -696,24 +745,32 @@
 		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 @@
 	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,45 +798,28 @@
 {
 	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 -Nru a/drivers/input/keyboard/hpps2atkbd.h b/drivers/input/keyboard/hpps2atkbd.h
--- a/drivers/input/keyboard/hpps2atkbd.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/input/keyboard/hpps2atkbd.h	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/keyboard/lkkbd.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
--- a/drivers/input/keyboard/maple_keyb.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/input/keyboard/maple_keyb.c	Sat Apr  3 19:38:42 2004
@@ -1,5 +1,5 @@
 /*
- *	$Id: maple_keyb.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $
+ *	$Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
  * 	SEGA Dreamcast keyboard driver
  *	Based on drivers/usb/usbkbd.c
  */
@@ -125,8 +125,11 @@
 
 	kbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
 
+	init_input_dev(&kbd->dev);
+
 	for (i=0; i<255; i++)
 		set_bit(dc_kbd_keycode[i], kbd->dev.keybit);
+
 	clear_bit(0, kbd->dev.keybit);
 
 	kbd->dev.private = kbd;
@@ -141,10 +144,7 @@
 
 	maple_getcond_callback(dev, dc_kbd_callback, 1, MAPLE_FUNC_KEYBOARD);
 
-	printk(KERN_INFO "input%d: keyboard(0x%lx): %s\n",
-	       kbd->dev.number, data, kbd->dev.name);
-
-	MOD_INC_USE_COUNT;
+	printk(KERN_INFO "input: keyboard(0x%lx): %s\n", data, kbd->dev.name);
 
 	return 0;
 }
@@ -155,10 +155,7 @@
 	struct dc_kbd *kbd = dev->private_data;
 
 	input_unregister_device(&kbd->dev);
-
 	kfree(kbd);
-
-	MOD_DEC_USE_COUNT;
 }
 
 
diff -Nru a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
--- a/drivers/input/keyboard/sunkbd.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/input/keyboard/sunkbd.c	Sat Apr  3 19:38:40 2004
@@ -77,6 +77,7 @@
 	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 @@
 
 	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_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 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 @@
 	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 @@
 		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 -Nru a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
--- a/drivers/input/misc/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/drivers/input/misc/Kconfig	Sat Apr  3 19:38:43 2004
@@ -54,12 +54,3 @@
 	  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 -Nru a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
--- a/drivers/input/misc/Makefile	Sat Apr  3 19:38:44 2004
+++ b/drivers/input/misc/Makefile	Sat Apr  3 19:38:44 2004
@@ -9,4 +9,3 @@
 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 -Nru a/drivers/input/misc/gsc_ps2.c b/drivers/input/misc/gsc_ps2.c
--- a/drivers/input/misc/gsc_ps2.c	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/drivers/input/mouse/98busmouse.c b/drivers/input/mouse/98busmouse.c
--- a/drivers/input/mouse/98busmouse.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/input/mouse/98busmouse.c	Sat Apr  3 19:38:55 2004
@@ -74,6 +74,8 @@
 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 -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
--- a/drivers/input/mouse/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/drivers/input/mouse/Kconfig	Sat Apr  3 19:38:55 2004
@@ -17,6 +17,7 @@
 	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
@@ -116,6 +117,19 @@
 
 	  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"
diff -Nru a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
--- a/drivers/input/mouse/Makefile	Sat Apr  3 19:38:41 2004
+++ b/drivers/input/mouse/Makefile	Sat Apr  3 19:38:41 2004
@@ -13,5 +13,6 @@
 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 -Nru a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
--- a/drivers/input/mouse/inport.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/input/mouse/inport.c	Sat Apr  3 19:38:43 2004
@@ -85,6 +85,8 @@
 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 -Nru a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
--- a/drivers/input/mouse/logibm.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/input/mouse/logibm.c	Sat Apr  3 19:38:43 2004
@@ -75,6 +75,8 @@
 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 -Nru a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
--- a/drivers/input/mouse/maplemouse.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/input/mouse/maplemouse.c	Sat Apr  3 19:38:55 2004
@@ -1,5 +1,5 @@
 /*
- *	$Id: maplemouse.c,v 1.1 2001/11/02 17:27:32 jsimmons Exp $
+ *	$Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
  * 	SEGA Dreamcast mouse driver
  *	Based on drivers/usb/usbmouse.c
  */
@@ -74,22 +74,21 @@
 	mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
 	mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
 
+	init_input_dev(&mouse->dev);
+
 	mouse->dev.private = mouse;
 	mouse->dev.open = dc_mouse_open;
 	mouse->dev.close = dc_mouse_close;
 	mouse->dev.event = NULL;
 
 	mouse->dev.name = dev->product_name;
-	mouse->dev.idbus = BUS_MAPLE;
+	mouse->dev.id.bustype = BUS_MAPLE;
 	
 	input_register_device(&mouse->dev);
 
 	maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
 
-	printk(KERN_INFO "input%d: mouse(0x%lx): %s\n",
-	       mouse->dev.number, data, mouse->dev.name);
-
-	MOD_INC_USE_COUNT;
+	printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
 
 	return 0;
 }
@@ -100,10 +99,7 @@
 	struct dc_mouse *mouse = dev->private_data;
 
 	input_unregister_device(&mouse->dev);
-
 	kfree(mouse);
-
-	MOD_DEC_USE_COUNT;
 }
 
 
diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/input/mouse/psmouse-base.c	Sat Apr  3 19:38:42 2004
@@ -47,6 +47,12 @@
 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 @@
 		       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 @@
 			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 */
@@ -281,6 +287,24 @@
 	return 0;
 }
 
+
+/*
+ * psmouse_reset() resets the mouse into power-on state.
+ */
+int psmouse_reset(struct psmouse *psmouse)
+{
+	unsigned char param[2];
+
+	if (psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT))
+		return -1;
+
+	if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
+		return -1;
+
+	return 0;
+}
+
+
 /*
  * Genius NetMouse magic init.
  */
@@ -365,6 +389,10 @@
  */
 			psmouse_max_proto = PSMOUSE_IMEX;
 		}
+/*
+ * Make sure that touchpad is in relative mode, gestures (taps) are enabled
+ */
+		synaptics_reset(psmouse);
 	}
 
 	if (psmouse_max_proto > PSMOUSE_IMEX && genius_detect(psmouse)) {
@@ -410,6 +438,7 @@
  * pass through port it could get disabled while probing for protocol
  * extensions.
  */
+		psmouse_reset(psmouse);
 		psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS);
 	}
 
@@ -442,7 +471,7 @@
  */
 
 	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 +526,7 @@
 static void psmouse_initialize(struct psmouse *psmouse)
 {
 	unsigned char param[2];
-	
+
 /*
  * We set the mouse report rate, resolution and scaling.
  */
@@ -534,8 +563,8 @@
 static void psmouse_cleanup(struct serio *serio)
 {
 	struct psmouse *psmouse = serio->private;
-	unsigned char param[2];
-	psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT);
+
+	psmouse_reset(psmouse);
 }
 
 /*
@@ -546,7 +575,7 @@
 {
 	struct psmouse *psmouse = serio->private;
 
-	psmouse->state = PSMOUSE_IGNORE;
+	psmouse->state = PSMOUSE_CMD_MODE;
 
 	if (psmouse->ptport) {
 		if (psmouse->ptport->deactivate)
@@ -559,6 +588,8 @@
 	if (psmouse->disconnect)
 		psmouse->disconnect(psmouse);
 
+	psmouse->state = PSMOUSE_IGNORE;
+
 	input_unregister_device(&psmouse->dev);
 	serio_close(serio);
 	kfree(psmouse);
@@ -571,7 +602,7 @@
 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;
@@ -586,7 +617,7 @@
 	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 
-	psmouse->state = PSMOUSE_NEW_DEVICE;
+	psmouse->state = PSMOUSE_CMD_MODE;
 	psmouse->serio = serio;
 	psmouse->dev.private = psmouse;
 
@@ -603,7 +634,7 @@
 		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 +648,7 @@
 	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,14 +668,16 @@
 {
 	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;
 	}
 
-	psmouse->state = PSMOUSE_NEW_DEVICE;
+	old_type = psmouse->type;
+
+	psmouse->state = PSMOUSE_CMD_MODE;
 	psmouse->type = psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = 0;
 	if (psmouse->reconnect) {
 	       if (psmouse->reconnect(psmouse))
diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
--- a/drivers/input/mouse/psmouse.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/input/mouse/psmouse.h	Sat Apr  3 19:38:55 2004
@@ -5,7 +5,7 @@
 #define PSMOUSE_CMD_SETRES	0x10e8
 #define PSMOUSE_CMD_GETINFO	0x03e9
 #define PSMOUSE_CMD_SETSTREAM	0x00ea
-#define PSMOUSE_CMD_POLL	0x03eb	
+#define PSMOUSE_CMD_POLL	0x03eb
 #define PSMOUSE_CMD_GETID	0x02f2
 #define PSMOUSE_CMD_SETRATE	0x10f3
 #define PSMOUSE_CMD_ENABLE	0x00f4
@@ -18,7 +18,7 @@
 #define PSMOUSE_RET_NAK		0xfe
 
 /* psmouse states */
-#define PSMOUSE_NEW_DEVICE	0
+#define PSMOUSE_CMD_MODE	0
 #define PSMOUSE_ACTIVATED	1
 #define PSMOUSE_IGNORE		2
 
@@ -65,6 +65,7 @@
 #define PSMOUSE_SYNAPTICS 	7
 
 int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
+int psmouse_reset(struct psmouse *psmouse);
 
 extern int psmouse_smartscroll;
 extern unsigned int psmouse_rate;
diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/input/mouse/synaptics.c	Sat Apr  3 19:38:42 2004
@@ -92,17 +92,6 @@
 	return 0;
 }
 
-static int synaptics_reset(struct psmouse *psmouse)
-{
-	unsigned char r[2];
-
-	if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
-		return -1;
-	if (r[0] == PSMOUSE_RET_BAT && r[1] == PSMOUSE_RET_ID)
-		return 0;
-	return -1;
-}
-
 /*
  * Read the model-id bytes from the touchpad
  * see also SYN_MODEL_* macros
@@ -197,7 +186,7 @@
 {
 	int retries = 0;
 
-	while ((retries++ < 3) && synaptics_reset(psmouse))
+	while ((retries++ < 3) && psmouse_reset(psmouse))
 		printk(KERN_ERR "synaptics reset failed\n");
 
 	if (synaptics_identify(psmouse))
@@ -368,9 +357,15 @@
 	clear_bit(REL_Y, dev->relbit);
 }
 
-static void synaptics_disconnect(struct psmouse *psmouse)
+void synaptics_reset(struct psmouse *psmouse)
 {
+	/* reset touchpad back to relative mode, gestures enabled */
 	synaptics_mode_cmd(psmouse, 0);
+}
+
+static void synaptics_disconnect(struct psmouse *psmouse)
+{
+	synaptics_reset(psmouse);
 	kfree(psmouse->private);
 }
 
@@ -435,6 +430,8 @@
 		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 +599,42 @@
 	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];
 
-	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];
+		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];
+
+		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 +650,17 @@
 			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 -Nru a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
--- a/drivers/input/mouse/synaptics.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/input/mouse/synaptics.h	Sat Apr  3 19:38:43 2004
@@ -12,6 +12,7 @@
 extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
 extern int synaptics_detect(struct psmouse *psmouse);
 extern int synaptics_init(struct psmouse *psmouse);
+extern void synaptics_reset(struct psmouse *psmouse);
 
 /* synaptics queries */
 #define SYN_QUE_IDENTIFY		0x00
@@ -70,6 +71,12 @@
 #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 +110,7 @@
 	/* 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 -Nru a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/mouse/vsxxxaa.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
--- a/drivers/input/serio/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/drivers/input/serio/Kconfig	Sat Apr  3 19:38:43 2004
@@ -20,6 +20,7 @@
 	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_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
@@ -104,6 +106,20 @@
 
 	  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"
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile	Sat Apr  3 19:38:41 2004
+++ b/drivers/input/serio/Makefile	Sat Apr  3 19:38:41 2004
@@ -14,4 +14,5 @@
 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 -Nru a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/input/serio/gscps2.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
--- a/drivers/input/serio/i8042-io.h	Sat Apr  3 19:38:40 2004
+++ b/drivers/input/serio/i8042-io.h	Sat Apr  3 19:38:40 2004
@@ -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 -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/input/serio/i8042.c	Sat Apr  3 19:38:41 2004
@@ -52,6 +52,13 @@
 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 @@
 	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 @@
 irq_ret:
 	ret = 1;
 out:
-	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 	return IRQ_RETVAL(ret);
 }
 
@@ -521,6 +529,11 @@
 	unsigned char mux_version;
 
 	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",
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/input/serio/serio.c	Sat Apr  3 19:38:40 2004
@@ -195,6 +195,9 @@
                 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 -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
--- a/drivers/isdn/capi/capi.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/isdn/capi/capi.c	Sat Apr  3 19:38:56 2004
@@ -1,4 +1,4 @@
-/* $Id: capi.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $
+/* $Id: capi.c,v 1.1.2.4 2004/03/29 10:38:02 armin Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
@@ -44,7 +44,7 @@
 #include "capifs.h"
 #endif
 
-static char *revision = "$Revision: 1.1.2.3 $";
+static char *revision = "$Revision: 1.1.2.4 $";
 
 MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
 MODULE_AUTHOR("Carsten Paeth");
@@ -200,7 +200,6 @@
 static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
 {
 	struct capiminor *mp, *p;
-	struct list_head *l;
 	unsigned int minor = 0;
 	unsigned long flags;
 
@@ -219,26 +218,31 @@
 	skb_queue_head_init(&mp->inqueue);
 	skb_queue_head_init(&mp->outqueue);
 
+	/* Allocate the least unused minor number.
+	 */
 	write_lock_irqsave(&capiminor_list_lock, flags);
-	if (list_empty(&capiminor_list)) {
+	if (list_empty(&capiminor_list))
 		list_add(&mp->list, &capiminor_list);
-		write_unlock_irqrestore(&capiminor_list_lock, flags);
-	} else {
-		list_for_each(l, &capiminor_list) {
-			p = list_entry(l, struct capiminor, list);
-			if (p->minor > minor) {
-				mp->minor = minor;
-				list_add_tail(&mp->list, &p->list);
+	else {
+		list_for_each_entry(p, &capiminor_list, list) {
+			if (p->minor > minor)
 				break;
-			}
 			minor++;
 		}
+		
+		if (minor < capi_ttyminors) {
+			mp->minor = minor;
+			list_add(&mp->list, p->list.prev);
+		}
+	}
 		write_unlock_irqrestore(&capiminor_list_lock, flags);
-		if (l == &capiminor_list) {
+
+	if (!(minor < capi_ttyminors)) {
+		printk(KERN_NOTICE "capi: out of minors\n");
 			kfree(mp);
-			return NULL;
-		}
+		return 0;
 	}
+
 	return mp;
 }
 
diff -Nru a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
--- a/drivers/isdn/capi/kcapi.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/isdn/capi/kcapi.c	Sat Apr  3 19:38:55 2004
@@ -1,4 +1,4 @@
-/* $Id: kcapi.c,v 1.1.2.4 2004/02/10 01:07:11 keil Exp $
+/* $Id: kcapi.c,v 1.1.2.7 2004/03/16 08:01:47 armin Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
@@ -31,7 +31,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.1.2.4 $";
+static char *revision = "$Revision: 1.1.2.7 $";
 
 /* ------------------------------------------------------------- */
 
@@ -45,7 +45,7 @@
 /* ------------------------------------------------------------- */
 
 struct capi_notifier {
-	struct capi_notifier *next;
+	struct work_struct work;
 	unsigned int cmd;
 	u32 controller;
 	u16 applid;
@@ -69,7 +69,6 @@
 static int ncards;
 static struct sk_buff_head recv_queue;
 
-static struct work_struct tq_state_notify;
 static struct work_struct tq_recv_notify;
 
 /* -------- controller ref counting -------------------------------------- */
@@ -161,79 +160,6 @@
 	capi_ctr_put(card);
 }
 
-
-/* -------- Notifier handling --------------------------------- */
-
-static struct capi_notifier_list{
-	struct capi_notifier *head;
-	struct capi_notifier *tail;
-} notifier_list;
-
-static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED;
-
-static inline void notify_enqueue(struct capi_notifier *np)
-{
-	struct capi_notifier_list *q = &notifier_list;
-	unsigned long flags;
-
-	spin_lock_irqsave(&notifier_lock, flags);
-	if (q->tail) {
-		q->tail->next = np;
-		q->tail = np;
-	} else {
-		q->head = q->tail = np;
-	}
-	spin_unlock_irqrestore(&notifier_lock, flags);
-}
-
-static inline struct capi_notifier *notify_dequeue(void)
-{
-	struct capi_notifier_list *q = &notifier_list;
-	struct capi_notifier *np = 0;
-	unsigned long flags;
-
-	spin_lock_irqsave(&notifier_lock, flags);
-	if (q->head) {
-		np = q->head;
-		if ((q->head = np->next) == 0)
- 			q->tail = 0;
-		np->next = 0;
-	}
-	spin_unlock_irqrestore(&notifier_lock, flags);
-	return np;
-}
-
-static int notify_push(unsigned int cmd, u32 controller,
-				u16 applid, u32 ncci)
-{
-	struct capi_notifier *np;
-
-	if (!try_module_get(THIS_MODULE)) {
-		printk(KERN_WARNING "%s: cannot reserve module\n", __FUNCTION__);
-		return -1;
-	}
-	np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
-	if (!np) {
-		module_put(THIS_MODULE);
-		return -1;
-	}
-	memset(np, 0, sizeof(struct capi_notifier));
-	np->cmd = cmd;
-	np->controller = controller;
-	np->applid = applid;
-	np->ncci = ncci;
-	notify_enqueue(np);
-	/*
-	 * The notifier will result in adding/deleteing
-	 * of devices. Devices can only removed in
-	 * user process, not in bh.
-	 */
-	__module_get(THIS_MODULE);
-	if (schedule_work(&tq_state_notify) == 0)
-		module_put(THIS_MODULE);
-	return 0;
-}
-
 /* -------- KCI_CONTRUP --------------------------------------- */
 
 static void notify_up(u32 contr)
@@ -242,7 +168,9 @@
 	struct capi20_appl *ap;
 	u16 applid;
 
-        printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
+	if (showcapimsgs & 1) {
+	        printk(KERN_DEBUG "kcapi: notify up contr %d\n", contr);
+	}
 
 	for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
 		ap = get_capi_appl_by_nr(applid);
@@ -258,7 +186,9 @@
 	struct capi20_appl *ap;
 	u16 applid;
 
-        printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
+	if (showcapimsgs & 1) {
+        	printk(KERN_DEBUG "kcapi: notify down contr %d\n", contr);
+	}
 
 	for (applid = 1; applid <= CAPI_MAXAPPL; applid++) {
 		ap = get_capi_appl_by_nr(applid);
@@ -267,31 +197,43 @@
 	}
 }
 
-/* ------------------------------------------------------------ */
-
-static inline void notify_doit(struct capi_notifier *np)
+static void notify_handler(void *data)
 {
+	struct capi_notifier *np = data;
+
 	switch (np->cmd) {
-		case KCI_CONTRUP:
-			notify_up(np->controller);
-			break;
-		case KCI_CONTRDOWN:
-			notify_down(np->controller);
-			break;
+	case KCI_CONTRUP:
+		notify_up(np->controller);
+		break;
+	case KCI_CONTRDOWN:
+		notify_down(np->controller);
+		break;
 	}
+
+	kfree(np);
 }
 
-static void notify_handler(void *dummy)
+/*
+ * The notifier will result in adding/deleteing of devices. Devices can
+ * only removed in user process, not in bh.
+ */
+static int notify_push(unsigned int cmd, u32 controller, u16 applid, u32 ncci)
 {
-	struct capi_notifier *np;
+	struct capi_notifier *np = kmalloc(sizeof(*np), GFP_ATOMIC);
 
-	while ((np = notify_dequeue()) != 0) {
-		notify_doit(np);
-		kfree(np);
-		module_put(THIS_MODULE);
-	}
-	module_put(THIS_MODULE);
+	if (!np)
+		return -ENOMEM;
+
+	INIT_WORK(&np->work, notify_handler, np);
+	np->cmd = cmd;
+	np->controller = controller;
+	np->applid = applid;
+	np->ncci = ncci;
+
+	schedule_work(&np->work);
+	return 0;
 }
+
 	
 /* -------- Receiver ------------------------------------------ */
 
@@ -304,7 +246,7 @@
 		ap = get_capi_appl_by_nr(CAPIMSG_APPID(skb->data));
 		if (!ap) {
 			printk(KERN_ERR "kcapi: recv_handler: applid %d ? (%s)\n",
-			       ap->applid, capi_message2str(skb->data));
+				CAPIMSG_APPID(skb->data), capi_message2str(skb->data));
 			kfree_skb(skb);
 			continue;
 		}
@@ -565,7 +507,9 @@
 			continue;
 		register_appl(capi_cards[i], applid, &ap->rparam);
 	}
-	printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
+	if (showcapimsgs & 1) {
+		printk(KERN_DEBUG "kcapi: appl %d up\n", applid);
+	}
 
 	return CAPI_NOERROR;
 }
@@ -584,7 +528,9 @@
 		release_appl(capi_cards[i], ap->applid);
 	}
 	capi_applications[ap->applid - 1] = NULL;
-	printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
+	if (showcapimsgs & 1) {
+		printk(KERN_DEBUG "kcapi: appl %d down\n", ap->applid);
+	}
 
 	return CAPI_NOERROR;
 }
@@ -981,7 +927,6 @@
 
 	skb_queue_head_init(&recv_queue);
 
-	INIT_WORK(&tq_state_notify, notify_handler, NULL);
 	INIT_WORK(&tq_recv_notify, recv_handler, NULL);
 
         kcapi_proc_init();
@@ -1001,6 +946,9 @@
 static void __exit kcapi_exit(void)
 {
         kcapi_proc_exit();
+
+	/* make sure all notifiers are finished */
+	flush_scheduled_work();
 }
 
 module_init(kcapi_init);
diff -Nru a/drivers/isdn/hardware/eicon/adapter.h b/drivers/isdn/hardware/eicon/adapter.h
--- a/drivers/isdn/hardware/eicon/adapter.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/isdn/hardware/eicon/adapter.h	Sat Apr  3 19:38:55 2004
@@ -1,4 +1,4 @@
-/* $Id: adapter.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $ */
+/* $Id: adapter.h,v 1.4 2004/03/21 17:26:01 armin Exp $ */
 
 #ifndef __DIVA_USER_MODE_IDI_ADAPTER_H__
 #define __DIVA_USER_MODE_IDI_ADAPTER_H__
@@ -6,10 +6,10 @@
 #define DIVA_UM_IDI_ADAPTER_REMOVED 0x00000001
 
 typedef struct _diva_um_idi_adapter {
-	diva_entity_link_t link;
+	struct list_head link;
 	DESCRIPTOR d;
 	int adapter_nr;
-	diva_entity_queue_t entity_q;	/* entities linked to this adapter */
+	struct list_head entity_q;	/* entities linked to this adapter */
 	dword status;
 } diva_um_idi_adapter_t;
 
diff -Nru a/drivers/isdn/hardware/eicon/capifunc.c b/drivers/isdn/hardware/eicon/capifunc.c
--- a/drivers/isdn/hardware/eicon/capifunc.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/isdn/hardware/eicon/capifunc.c	Sat Apr  3 19:38:55 2004
@@ -1,4 +1,4 @@
-/* $Id: capifunc.c,v 1.48 2004/01/11 19:20:54 armin Exp $
+/* $Id: capifunc.c,v 1.61 2004/03/26 19:48:48 armin Exp $
  *
  * ISDN interface module for Eicon active cards DIVA.
  * CAPI Interface common functions
@@ -39,9 +39,9 @@
 extern word api_put(APPL *, CAPI_MSG *);
 
 static diva_os_spin_lock_t api_lock;
-static diva_os_spin_lock_t ll_lock;
 
-static diva_card *cards;
+static LIST_HEAD(cards);
+
 static dword notify_handle;
 static void DIRequest(ENTITY * e);
 static DESCRIPTOR MAdapter;
@@ -152,26 +152,15 @@
 static int find_free_id(void)
 {
 	int num = 0;
-	diva_card *p;
-	diva_os_spin_lock_magic_t old_irql;
+	DIVA_CAPI_ADAPTER *a;
 
-	diva_os_enter_spin_lock(&ll_lock, &old_irql, "find free id");
-	while (num < 100) {
-		num++;
-		p = cards;
-		while (p) {
-			if (p->Id == num)
+	while (num < MAX_DESCRIPTORS) {
+		a = &adapter[num];
+		if (!a->Id)
 				break;
-			p = p->next;
-		}
-		if(!p) {
-		diva_os_leave_spin_lock(&ll_lock, &old_irql,
-					"find free id");
-		return (num);
-		}
+		num++;
 	}
-	diva_os_leave_spin_lock(&ll_lock, &old_irql, "find free id");
-	return (999);
+	return(num + 1);
 }
 
 /*
@@ -179,21 +168,17 @@
  */
 static diva_card *find_card_by_ctrl(word controller)
 {
-	diva_card *p;
-	diva_os_spin_lock_magic_t old_irql;
-
-	diva_os_enter_spin_lock(&ll_lock, &old_irql, "find card ctrl");
-	p = cards;
+	struct list_head *tmp;
+	diva_card *card;
 
-	while (p) {
-		if (ControllerMap[p->Id] == controller) {
-			diva_os_leave_spin_lock(&ll_lock, &old_irql,
-						"find card ctrl");
-			return p;
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, diva_card, list);
+		if (ControllerMap[card->Id] == controller) {
+			if (card->remove_in_progress)
+				card = NULL;
+			return(card);
 		}
-		p = p->next;
 	}
-	diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card ctrl");
 	return (diva_card *) 0;
 }
 
@@ -358,28 +343,18 @@
 /*
  * cleanup adapter
  */
-static void clean_adapter(int id)
+static void clean_adapter(int id, struct list_head *free_mem_q)
 {
 	DIVA_CAPI_ADAPTER *a;
-#if IMPLEMENT_LINE_INTERCONNECT2
 	int i, k;
-#endif				/* IMPLEMENT_LINE_INTERCONNECT2 */
 
 	a = &adapter[id];
-#if IMPLEMENT_LINE_INTERCONNECT
-	if (a->li_pri) {
-		if (a->li_config.pri)
-			diva_os_free(0, a->li_config.pri);
-	} else {
-		if (a->li_config.bri)
-			diva_os_free(0, a->li_config.bri);
-	}
-#endif				/* IMPLEMENT_LINE_INTERCONNECT */
-#if IMPLEMENT_LINE_INTERCONNECT2
 	k = li_total_channels - a->li_channels;
 	if (k == 0) {
-		diva_os_free(0, li_config_table);
+		if (li_config_table) {
+			list_add((struct list_head *)li_config_table, free_mem_q);
 		li_config_table = NULL;
+		}
 	} else {
 		if (a->li_base < k) {
 			memmove(&li_config_table[a->li_base],
@@ -401,9 +376,8 @@
 		if (adapter[i].request)
 			adapter[i].li_base -= a->li_channels;
 	}
-#endif				/* IMPLEMENT_LINE_INTERCONNECT2 */
 	if (a->plci)
-		diva_os_free(0, a->plci);
+		list_add((struct list_head *)a->plci, free_mem_q);
 
 	memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER));
 	while ((max_adapter != 0) && !adapter[max_adapter - 1].request)
@@ -411,67 +385,85 @@
 }
 
 /*
- * remove cards
+ * remove a card, but ensures consistent state of LI tables
+ * in the time adapter is removed
  */
-static void DIVA_EXIT_FUNCTION divacapi_remove_cards(void)
+static void divacapi_remove_card(DESCRIPTOR * d)
 {
-	diva_card *last;
-	diva_card *card;
+	diva_card *card = NULL;
 	diva_os_spin_lock_magic_t old_irql;
+	LIST_HEAD(free_mem_q);
+	struct list_head *link;
+	struct list_head *tmp;
+
+	/*
+	 * Set "remove in progress flag".
+	 * Ensures that there is no call from sendf to CAPI in
+	 * the time CAPI controller is about to be removed.
+	 */
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, diva_card, list);
+		if (card->d.request == d->request) {
+			card->remove_in_progress = 1;
+			list_del(tmp);
+			break;
+		}
+	}
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");
 
-	diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove cards");
-	card = cards;
-
-	while (card) {
+	if (card) {
+		/*
+		 * Detach CAPI. Sendf cannot call to CAPI any more.
+		 * After detach no call to send_message() is done too.
+		 */
 		detach_capi_ctr(&card->capi_ctrl);
-		clean_adapter(card->Id - 1);
-		DBG_TRC(("adapter remove, max_adapter=%d", max_adapter));
-		card = card->next;
-	}
 
-	card = cards;
-	while (card) {
-		last = card;
-		card = card->next;
-		diva_os_free(0, last);
+		/*
+		 * Now get API lock (to ensure stable state of LI tables)
+		 * and update the adapter map/LI table.
+		 */
+		diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");
+
+		clean_adapter(card->Id - 1, &free_mem_q);
+		DBG_TRC(("DelAdapterMap (%d) -> (%d)",
+				ControllerMap[card->Id], card->Id))
+				ControllerMap[card->Id] = 0;
+		DBG_TRC(("adapter remove, max_adapter=%d",
+				max_adapter));
+		diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");
+		
+		/* After releasing the lock, we can free the memory */
+		diva_os_free (0, card);
+	}
+
+	/* free queued memory areas */
+	list_for_each_safe(link, tmp, &free_mem_q) {
+		list_del(link);
+		diva_os_free(0, link);
 	}
-	diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove cards");
 }
 
 /*
- * remove a card
+ * remove cards
  */
-static void divacapi_remove_card(DESCRIPTOR * d)
+static void divacapi_remove_cards(void)
 {
-	diva_card *last;
+	DESCRIPTOR d;
+	struct list_head *tmp;
 	diva_card *card;
 	diva_os_spin_lock_magic_t old_irql;
 
-	diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card");
-	last = card = cards;
-	while (card) {
-		if (card->d.request == d->request) {
-			detach_capi_ctr(&card->capi_ctrl);
-			clean_adapter(card->Id - 1);
-			DBG_TRC(
-				("DelAdapterMap (%d) -> (%d)",
-				 ControllerMap[card->Id], card->Id))
-			    ControllerMap[card->Id] = 0;
-			DBG_TRC(
-				("adapter remove, max_adapter=%d",
-				 max_adapter));
-			if (card == last)
-				cards = card->next;
-			else
-				last->next = card->next;
-
-			diva_os_free(0, card);
-			break;
-		}
-		last = card;
-		card = card->next;
+rescan:
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards");
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, diva_card, list);
+		diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");
+		d.request = card->d.request;
+		divacapi_remove_card(&d);
+		goto rescan;
 	}
-	diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card");
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");
 }
 
 /*
@@ -500,10 +492,9 @@
 	DIVA_CAPI_ADAPTER *a = NULL;
 	IDI_SYNC_REQ sync_req;
 	char serial[16];
-#if IMPLEMENT_LINE_INTERCONNECT2
+	void* mem_to_free;
 	LI_CONFIG *new_li_config_table;
 	int j;
-#endif				/* IMPLEMENT_LINE_INTERCONNECT2 */
 
 	if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) {
 		DBG_ERR(("diva_add_card: failed to allocate card struct."))
@@ -529,7 +520,11 @@
 		    diva_os_free(0, card);
 		return (0);
 	}
+	
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "find id");
 	card->Id = find_free_id();
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "find id");
+	
 	strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu));
 	ctrl->version.majorversion = 2;
 	ctrl->version.minorversion = 0;
@@ -600,9 +595,7 @@
 #if IMPLEMENT_DTMF
 		a->profile.Global_Options |= 0x8;
 #endif				/* IMPLEMENT_DTMF */
-#if (IMPLEMENT_LINE_INTERCONNECT || IMPLEMENT_LINE_INTERCONNECT2)
-		a->profile.Global_Options |= 0x80;
-#endif				/* (IMPLEMENT_LINE_INTERCONNECT || IMPLEMENT_LINE_INTERCONNECT2) */
+		a->profile.Global_Options |= 0x80; /* Line Interconnect */
 #if IMPLEMENT_ECHO_CANCELLER
 		a->profile.Global_Options |= 0x100;
 #endif				/* IMPLEMENT_ECHO_CANCELLER */
@@ -620,25 +613,6 @@
 		a->manufacturer_features = 0;
 	}
 
-#if IMPLEMENT_LINE_INTERCONNECT
-	a->li_pri = (a->profile.Channels > 2);
-	if (a->li_pri) {
-		if (!(a->li_config.pri = (LI_CONFIG_PRI *) diva_os_malloc(0, sizeof(LI_CONFIG_PRI)))) {
-			DBG_ERR(("diva_add_card: failed alloc li_config.pri struct."))
-			memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
-			return (0);
-		}
-		memset(a->li_config.pri, 0, sizeof(LI_CONFIG_PRI));
-	} else 
-		if (!(a->li_config.bri = (LI_CONFIG_BRI *) diva_os_malloc(0, sizeof(LI_CONFIG_BRI)))) {
-			DBG_ERR(("diva_add_card: failed alloc li_config.bri struct."))
-			memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
-			return (0);
-		}
-		memset(a->li_config.bri, 0, sizeof(LI_CONFIG_BRI));
-	}
-#endif				/* IMPLEMENT_LINE_INTERCONNECT */
-#if IMPLEMENT_LINE_INTERCONNECT2
 	a->li_pri = (a->profile.Channels > 2);
 	a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI;
 	a->li_base = 0;
@@ -654,6 +628,10 @@
 		memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
 		return (0);
 	}
+
+	/* Prevent access to line interconnect table in process update */
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "add card");
+	
 	j = 0;
 	for (i = 0; i < k; i++) {
 		if ((i >= a->li_base) && (i < a->li_base + a->li_channels))
@@ -694,25 +672,26 @@
 	}
 	li_total_channels = k;
 
-	if (li_config_table != NULL)
-		diva_os_free(0, li_config_table);
+	mem_to_free = li_config_table;
 
 	li_config_table = new_li_config_table;
 	for (i = card->Id; i < max_adapter; i++) {
 		if (adapter[i].request)
 			adapter[i].li_base += a->li_channels;
 	}
-#endif				/* IMPLEMENT_LINE_INTERCONNECT2 */
 
 	if (a == &adapter[max_adapter])
 		max_adapter++;
 
-	diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card");
-	card->next = cards;
-	cards = card;
-	diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card");
-
+	list_add(&(card->list), &cards);
 	AutomaticLaw(a);
+
+	diva_os_leave_spin_lock(&api_lock, &old_irql, "add card");
+
+	if (mem_to_free) {
+		diva_os_free (0, mem_to_free);
+	}
+
 	i = 0;
 	while (i++ < 30) {
 		if (a->automatic_law > 3)
@@ -863,6 +842,7 @@
 {
 	diva_os_spin_lock_magic_t old_irql;
 	APPL *this = &application[appl - 1];
+	void *mem_to_free = NULL;
 
 	DBG_TRC(("application %d(%d) cleanup", this->Id, appl))
 
@@ -874,13 +854,15 @@
 	diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl");
 	if (this->Id) {
 		CapiRelease(this->Id);
-		if (this->DataNCCI)
-			diva_os_free(0, this->DataNCCI);
+		mem_to_free = this->DataNCCI;
 		this->DataNCCI = NULL;
 		this->Id = 0;
 	}
 	diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl");
 
+	if (mem_to_free)
+		diva_os_free(0, mem_to_free);
+
 }
 
 /*
@@ -906,7 +888,15 @@
 	}
 	DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command))
 
+	if (card->remove_in_progress) {
+		DBG_ERR(("CAPI_SEND_MSG - remove in progress!"))
+		return CAPI_REGOSRESOURCEERR;
+	}
+
+	diva_os_enter_spin_lock(&api_lock, &old_irql, "send message");
+
 	if (!this->Id) {
+		diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");
 		return CAPI_ILLAPPNR;
 	}
 
@@ -914,8 +904,6 @@
 	msg->header.controller = ControllerMap[card->Id]
 	    | (msg->header.controller & 0x80);	/* preserve external controller bit */
 
-	diva_os_enter_spin_lock(&api_lock, &old_irql, "send message");
-
 	switch (command) {
 	default:
 		xlog("\x00\x02", msg, 0x80, clength);
@@ -1163,11 +1151,30 @@
 }
 
 /*
+ * api_remove_start
+ */
+static void do_api_remove_start(void)
+{
+	diva_os_spin_lock_magic_t old_irql;
+	int ret = 1, count = 100;
+
+	do {
+		diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start");
+		ret = api_remove_start();
+		diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start");
+
+		diva_os_sleep(10);
+	} while (ret && count--);
+
+	if (ret)
+		DBG_ERR(("could not remove signaling ID's"))
+}
+
+/*
  * init
  */
 int DIVA_INIT_FUNCTION init_capifunc(void)
 {
-	diva_os_initialize_spin_lock(&ll_lock, "capifunc");
 	diva_os_initialize_spin_lock(&api_lock, "capifunc");
 	memset(ControllerMap, 0, MAX_DESCRIPTORS + 1);
 	max_adapter = 0;
@@ -1175,12 +1182,16 @@
 
 	if (!init_main_structs()) {
 		DBG_ERR(("init: failed to init main structs."))
+		diva_os_destroy_spin_lock(&api_lock, "capifunc");
 		return (0);
 	}
 
 	if (!divacapi_connect_didd()) {
 		DBG_ERR(("init: failed to connect to DIDD."))
+		do_api_remove_start();
+		divacapi_remove_cards();
 		remove_main_structs();
+		diva_os_destroy_spin_lock(&api_lock, "capifunc");
 		return (0);
 	}
 
@@ -1192,21 +1203,9 @@
  */
 void DIVA_EXIT_FUNCTION finit_capifunc(void)
 {
-	int count = 100;
-	word ret = 1;
-
-	while (ret && count--) {
-		ret = api_remove_start();
-		diva_os_sleep(10);
-	}
-	if (ret)
-		DBG_ERR(("could not remove signaling ID's"))
-
+	do_api_remove_start();
 		    divacapi_disconnect_didd();
 	divacapi_remove_cards();
-
 	remove_main_structs();
-
 	diva_os_destroy_spin_lock(&api_lock, "capifunc");
-	diva_os_destroy_spin_lock(&ll_lock, "capifunc");
 }
diff -Nru a/drivers/isdn/hardware/eicon/capifunc.h b/drivers/isdn/hardware/eicon/capifunc.h
--- a/drivers/isdn/hardware/eicon/capifunc.h	Sat Apr  3 19:38:54 2004
+++ b/drivers/isdn/hardware/eicon/capifunc.h	Sat Apr  3 19:38:54 2004
@@ -1,4 +1,4 @@
-/* $Id: capifunc.h,v 1.10 2003/08/25 10:06:37 schindler Exp $
+/* $Id: capifunc.h,v 1.11 2004/03/20 17:19:58 armin Exp $
  *
  * ISDN interface module for Eicon active cards DIVA.
  * CAPI Interface common functions
@@ -24,8 +24,9 @@
 extern char DRIVERRELEASE_CAPI[];
 
 typedef struct _diva_card {
+	struct list_head list;
+	int remove_in_progress;
 	int Id;
-	struct _diva_card *next;
 	struct capi_ctr capi_ctrl;
 	DIVA_CAPI_ADAPTER *adapter;
 	DESCRIPTOR d;
diff -Nru a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c
--- a/drivers/isdn/hardware/eicon/diva.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/isdn/hardware/eicon/diva.c	Sat Apr  3 19:38:55 2004
@@ -1,4 +1,4 @@
-/* $Id: diva.c,v 1.17 2003/09/09 06:52:01 schindler Exp $ */
+/* $Id: diva.c,v 1.21 2004/03/21 17:30:25 armin Exp $ */
 
 #define CARDTYPE_H_WANT_DATA            1
 #define CARDTYPE_H_WANT_IDI_DATA        0
@@ -8,7 +8,6 @@
 #include "platform.h"
 #include "debuglib.h"
 #include "cardtype.h"
-#include "dlist.h"
 #include "pc.h"
 #include "di_defs.h"
 #include "di.h"
@@ -75,14 +74,9 @@
 struct pt_regs;
 
 /*
- * include queue functions
- */
-#include "dlist.c"
-
-/*
 **  LOCALS
 */
-diva_entity_queue_t adapter_queue;
+static LIST_HEAD(adapter_queue);
 
 typedef struct _diva_get_xlog {
 	word command;
@@ -158,6 +152,16 @@
 	return (0);
 }
 
+static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head * what)
+{
+	diva_os_xdi_adapter_t *a = NULL;
+
+	if (what && !list_empty(what))
+		a = list_entry(what->next, diva_os_xdi_adapter_t, link);
+
+	return(a);
+}
+
 /* --------------------------------------------------------------------------
     Add card to the card list
    -------------------------------------------------------------------------- */
@@ -204,7 +208,7 @@
 					diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
 					pa = pdiva;
 					for (j = 1; j < nr; j++) {	/* slave adapters, if any */
-						pa = (diva_os_xdi_adapter_t *) diva_q_get_next(&pa->link);
+						pa = diva_q_get_next(&pa->link);
 						if (pa && !pa->interface.cleanup_adapter_proc) {
 							pa->controller = i + 1 + j;
 							pa->xdi_adapter.ANum = pa->controller;
@@ -246,7 +250,6 @@
 int divasa_xdi_driver_entry(void)
 {
 	diva_os_initialize_spin_lock(&adapter_lock, "adapter");
-	diva_q_init(&adapter_queue);
 	memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));
 	diva_init_request_array();
 
@@ -259,12 +262,14 @@
 static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)
 {
 	diva_os_spin_lock_magic_t old_irql;
-	diva_os_xdi_adapter_t *a;
+	diva_os_xdi_adapter_t *a = NULL;
 
 	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");
 
-	if ((a = (diva_os_xdi_adapter_t *) diva_q_get_head(&adapter_queue)))
-		diva_q_remove(&adapter_queue, &a->link);
+	if (!list_empty(&adapter_queue)) {
+		a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);
+		list_del(adapter_queue.next);
+	}
 
 	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
 	return (a);
@@ -286,7 +291,7 @@
 	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");
 
 	for (i = 1; i < 4; i++) {
-		if ((pa = (diva_os_xdi_adapter_t *) diva_q_get_next(&pa->link))
+		if ((pa = diva_q_get_next(&pa->link))
 		    && !pa->interface.cleanup_adapter_proc) {
 			a[i] = pa;
 		} else {
@@ -295,7 +300,7 @@
 	}
 
 	for (i = 0; ((i < 4) && a[i]); i++) {
-		diva_q_remove(&adapter_queue, &a[i]->link);
+		list_del(&a[i]->link);
 	}
 
 	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
@@ -345,12 +350,12 @@
 	   numbers as master adapter
 	 */
 	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
-	diva_q_add_tail(&adapter_queue, &a->link);
+	list_add_tail(&a->link, &adapter_queue);
 	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
 
 	if ((*(pI->init_card)) (a)) {
 		diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
-		diva_q_remove(&adapter_queue, &a->link);
+		list_del(&a->link);
 		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
 		diva_os_free(0, a);
 		DBG_ERR(("A: can't get adapter resources"));
@@ -383,21 +388,14 @@
 /*
 **  Receive and process command from user mode utility
 */
-static int cmp_adapter_nr(const void *what, const diva_entity_link_t * p)
-{
-	diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) p;
-	dword nr = (dword) (unsigned long) what;
-
-	return (nr != a->controller);
-}
-
 void *diva_xdi_open_adapter(void *os_handle, const void *src,
 			    int length,
 			    divas_xdi_copy_from_user_fn_t cp_fn)
 {
 	diva_xdi_um_cfg_cmd_t msg;
-	diva_os_xdi_adapter_t *a;
+	diva_os_xdi_adapter_t *a = NULL;
 	diva_os_spin_lock_magic_t old_irql;
+	struct list_head *tmp;
 
 	if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
 		DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
@@ -409,10 +407,12 @@
 		return (0);
 	}
 	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
-	a = (diva_os_xdi_adapter_t *) diva_q_find(&adapter_queue,
-						  (void *) (unsigned long)
-						  msg.adapter,
-						  cmp_adapter_nr);
+	list_for_each(tmp, &adapter_queue) {
+		a = list_entry(tmp, diva_os_xdi_adapter_t, link);
+		if (a->controller == (int)msg.adapter)
+			break;
+		a = NULL;
+	}
 	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");
 
 	if (!a) {
@@ -611,7 +611,7 @@
 	diva_os_spin_lock_magic_t old_irql;
 
 	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
-	diva_q_add_tail(&adapter_queue, &a->link);
+	list_add_tail(&a->link, &adapter_queue);
 	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
 }
 
diff -Nru a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
--- a/drivers/isdn/hardware/eicon/divasmain.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/isdn/hardware/eicon/divasmain.c	Sat Apr  3 19:38:41 2004
@@ -1,4 +1,4 @@
-/* $Id: divasmain.c,v 1.48 2004/02/24 17:46:28 armin Exp $
+/* $Id: divasmain.c,v 1.54 2004/04/02 18:59:22 armin Exp $
  *
  * Low level driver for Eicon DIVA Server ISDN cards.
  *
@@ -22,6 +22,7 @@
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
 #include <linux/poll.h>
 #include <linux/kmod.h>
 
@@ -29,7 +30,6 @@
 #undef ID_MASK
 #undef N_DATA
 #include "pc.h"
-#include "dlist.h"
 #include "di_defs.h"
 #include "divasync.h"
 #include "diva.h"
@@ -41,7 +41,7 @@
 #include "diva_dma.h"
 #include "diva_pci.h"
 
-static char *main_revision = "$Revision: 1.48 $";
+static char *main_revision = "$Revision: 1.54 $";
 
 static int major;
 
@@ -69,7 +69,7 @@
 extern void divasfunc_exit(void);
 
 typedef struct _diva_os_thread_dpc {
-	struct work_struct divas_task;
+	struct tasklet_struct divas_task;
 	struct work_struct trap_script_task;
 	diva_os_soft_isr_t *psoft_isr;
 	int card_failed;
@@ -552,7 +552,7 @@
 /* --------------------------------------------------------------------------
     DPC framework implementation
    -------------------------------------------------------------------------- */
-static void diva_os_dpc_proc(void *context)
+static void diva_os_dpc_proc(unsigned long context)
 {
 	diva_os_thread_dpc_t *psoft_isr = (diva_os_thread_dpc_t *) context;
 	diva_os_soft_isr_t *pisr = psoft_isr->psoft_isr;
@@ -575,7 +575,7 @@
 	psoft_isr->callback_context = callback_context;
 	pdpc->psoft_isr = psoft_isr;
 	INIT_WORK(&pdpc->trap_script_task, diva_adapter_trapped, pdpc);
-	INIT_WORK(&pdpc->divas_task, diva_os_dpc_proc, pdpc);
+	tasklet_init(&pdpc->divas_task, diva_os_dpc_proc, (unsigned long)pdpc);
 
 	return (0);
 }
@@ -586,7 +586,7 @@
 		diva_os_thread_dpc_t *pdpc =
 		    (diva_os_thread_dpc_t *) psoft_isr->object;
 
-		schedule_work(&pdpc->divas_task);
+		tasklet_schedule(&pdpc->divas_task);
 	}
 
 	return (1);
@@ -600,8 +600,11 @@
 void diva_os_remove_soft_isr(diva_os_soft_isr_t * psoft_isr)
 {
 	if (psoft_isr && psoft_isr->object) {
+		diva_os_thread_dpc_t *pdpc =
+		    (diva_os_thread_dpc_t *) psoft_isr->object;
 		void *mem;
 
+		tasklet_kill(&pdpc->divas_task);
 		flush_scheduled_work();
 		mem = psoft_isr->object;
 		psoft_isr->object = 0;
diff -Nru a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
--- a/drivers/isdn/hardware/eicon/divasproc.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/isdn/hardware/eicon/divasproc.c	Sat Apr  3 19:38:54 2004
@@ -1,4 +1,4 @@
-/* $Id: divasproc.c,v 1.18 2003/09/09 06:46:29 schindler Exp $
+/* $Id: divasproc.c,v 1.19 2004/03/21 17:26:01 armin Exp $
  *
  * Low level driver for Eicon DIVA Server ISDN cards.
  * /proc functions
@@ -15,10 +15,10 @@
 #include <linux/kernel.h>
 #include <linux/poll.h>
 #include <linux/proc_fs.h>
+#include <linux/list.h>
 
 #include "platform.h"
 #include "debuglib.h"
-#include "dlist.h"
 #undef ID_MASK
 #undef N_DATA
 #include "pc.h"
@@ -33,7 +33,6 @@
 
 
 extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
-extern diva_entity_queue_t adapter_queue;
 extern void divas_get_version(char *);
 extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
 
diff -Nru a/drivers/isdn/hardware/eicon/dlist.c b/drivers/isdn/hardware/eicon/dlist.c
--- a/drivers/isdn/hardware/eicon/dlist.c	Sat Apr  3 19:38:40 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,76 +0,0 @@
-/* $Id: dlist.c,v 1.6 2003/08/25 16:03:35 schindler Exp $ */
-
-#include "platform.h"
-#include "dlist.h"
-
-/*
-**  Initialize linked list
-*/
-
-static void diva_q_init(diva_entity_queue_t * q)
-{
-	memset(q, 0x00, sizeof(*q));
-}
-
-/*
-**  Remove element from linked list
-*/
-static void diva_q_remove(diva_entity_queue_t * q, diva_entity_link_t * what)
-{
-	if (!what->prev) {
-		if ((q->head = what->next)) {
-			q->head->prev = 0;
-		} else {
-			q->tail = 0;
-		}
-	} else if (!what->next) {
-		q->tail = what->prev;
-		q->tail->next = 0;
-	} else {
-		what->prev->next = what->next;
-		what->next->prev = what->prev;
-	}
-	what->prev = what->next = 0;
-}
-
-/*
-**  Add element to the tail of linked list
-*/
-static void diva_q_add_tail(diva_entity_queue_t * q, diva_entity_link_t * what)
-{
-	what->next = 0;
-	if (!q->head) {
-		what->prev = 0;
-		q->head = q->tail = what;
-	} else {
-		what->prev = q->tail;
-		q->tail->next = what;
-		q->tail = what;
-	}
-}
-
-static diva_entity_link_t *diva_q_find(const diva_entity_queue_t * q,
-				const void *what, diva_q_cmp_fn_t cmp_fn)
-{
-	diva_entity_link_t *diva_current = q->head;
-
-	while (diva_current) {
-		if (!(*cmp_fn) (what, diva_current)) {
-			break;
-		}
-		diva_current = diva_current->next;
-	}
-
-	return (diva_current);
-}
-
-static diva_entity_link_t *diva_q_get_head(diva_entity_queue_t * q)
-{
-	return (q->head);
-}
-
-static diva_entity_link_t *diva_q_get_next(diva_entity_link_t * what)
-{
-	return ((what) ? what->next : 0);
-}
-
diff -Nru a/drivers/isdn/hardware/eicon/dlist.h b/drivers/isdn/hardware/eicon/dlist.h
--- a/drivers/isdn/hardware/eicon/dlist.h	Sat Apr  3 19:38:56 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-/* $Id: dlist.h,v 1.5 2003/08/25 16:03:35 schindler Exp $ */
-
-#ifndef __DIVA_LINK_H__
-#define __DIVA_LINK_H__
-
-struct _diva_entity_link;
-typedef struct _diva_entity_link {
-	struct _diva_entity_link *prev;
-	struct _diva_entity_link *next;
-} diva_entity_link_t;
-
-typedef struct _diva_entity_queue {
-	diva_entity_link_t *head;
-	diva_entity_link_t *tail;
-} diva_entity_queue_t;
-
-typedef int (*diva_q_cmp_fn_t) (const void *what,
-				const diva_entity_link_t *);
-
-#endif
diff -Nru a/drivers/isdn/hardware/eicon/entity.h b/drivers/isdn/hardware/eicon/entity.h
--- a/drivers/isdn/hardware/eicon/entity.h	Sat Apr  3 19:38:44 2004
+++ b/drivers/isdn/hardware/eicon/entity.h	Sat Apr  3 19:38:44 2004
@@ -1,4 +1,4 @@
-/* $Id: entity.h,v 1.1.2.1 2001/02/08 12:25:43 armin Exp $ */
+/* $Id: entity.h,v 1.4 2004/03/21 17:26:01 armin Exp $ */
 
 #ifndef __DIVAS_USER_MODE_IDI_ENTITY__
 #define __DIVAS_USER_MODE_IDI_ENTITY__
@@ -10,7 +10,7 @@
 #define DIVA_UM_IDI_ASSIGN_PENDING  0x00000010
 
 typedef struct _divas_um_idi_entity {
-	diva_entity_link_t        link; /* should be first */
+	struct list_head          link;
 	diva_um_idi_adapter_t*    adapter; /* Back to adapter */
 	ENTITY                    e;
 	void*                     os_ref;
diff -Nru a/drivers/isdn/hardware/eicon/i4l_idi.c b/drivers/isdn/hardware/eicon/i4l_idi.c
--- a/drivers/isdn/hardware/eicon/i4l_idi.c	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3135 +0,0 @@
-/* $Id: i4l_idi.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
- *
- * ISDN interface module for Eicon active cards.
- * I4L - IDI Interface
- *
- * Copyright 1998-2000  by Armin Schindler (mac@melware.de)
- * Copyright 1999-2002  Cytronics & Melware (info@melware.de)
- *
- * Thanks to	Deutsche Mailbox Saar-Lor-Lux GmbH
- *		for sponsoring and testing fax
- *		capabilities with Diva Server cards.
- *		(dor@deutschemailbox.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#include <linux/config.h>
-#include "i4lididrv.h"
-
-#undef EICON_FULL_SERVICE_OKTETT
-
-char *eicon_idi_revision = "$Revision: 1.1.2.2 $";
-
-eicon_manifbuf *manbuf;
-
-static int eicon_idi_manage_assign(eicon_card *card);
-static int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer);
-
-static int
-idi_assign_req(eicon_REQ *reqbuf, int signet, eicon_chan *chan)
-{
-	int l = 0;
-	int tmp;
-
-	tmp = 0;
-  if (!signet) {
-	/* Signal Layer */
-	reqbuf->XBuffer.P[l++] = CAI;
-	reqbuf->XBuffer.P[l++] = 1;
-	reqbuf->XBuffer.P[l++] = 0;
-	reqbuf->XBuffer.P[l++] = KEY;
-	reqbuf->XBuffer.P[l++] = 3;
-	reqbuf->XBuffer.P[l++] = 'I';
-	reqbuf->XBuffer.P[l++] = '4';
-	reqbuf->XBuffer.P[l++] = 'L';
-	reqbuf->XBuffer.P[l++] = SHIFT|6;
-	reqbuf->XBuffer.P[l++] = SIN;
-	reqbuf->XBuffer.P[l++] = 2;
-	reqbuf->XBuffer.P[l++] = 0;
-	reqbuf->XBuffer.P[l++] = 0;
-	reqbuf->XBuffer.P[l++] = 0; /* end */
-	reqbuf->Req = ASSIGN;
-	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = DSIG_ID;
-	reqbuf->XBuffer.length = l;
-	reqbuf->Reference = 0; /* Sig Entity */
-  }
-  else {
-	/* Network Layer */
-	reqbuf->XBuffer.P[l++] = CAI;
-	reqbuf->XBuffer.P[l++] = 1;
-	reqbuf->XBuffer.P[l++] = chan->e.D3Id;
-	reqbuf->XBuffer.P[l++] = LLC;
-	reqbuf->XBuffer.P[l++] = 2;
-	switch(chan->l2prot) {
-		case ISDN_PROTO_L2_V11096:
-		case ISDN_PROTO_L2_V11019:
-		case ISDN_PROTO_L2_V11038:
-		case ISDN_PROTO_L2_TRANS:
-			reqbuf->XBuffer.P[l++] = 2; /* transparent */
-			break;
-		case ISDN_PROTO_L2_X75I:
-		case ISDN_PROTO_L2_X75UI:
-		case ISDN_PROTO_L2_X75BUI:
-			reqbuf->XBuffer.P[l++] = 5; /* X.75 */ 
-			break;
-		case ISDN_PROTO_L2_MODEM:
-  			  if (chan->fsm_state == EICON_STATE_IWAIT)
-				reqbuf->XBuffer.P[l++] = 9; /* V.42 incoming */
-  			  else
-				reqbuf->XBuffer.P[l++] = 10; /* V.42 */
-			  break;
-		case ISDN_PROTO_L2_HDLC:
-		case ISDN_PROTO_L2_FAX:
-  			if (chan->fsm_state == EICON_STATE_IWAIT)
-				reqbuf->XBuffer.P[l++] = 3; /* autoconnect on incoming */
-			else
-				reqbuf->XBuffer.P[l++] = 2; /* transparent */
-			break;
-		default:
-			reqbuf->XBuffer.P[l++] = 1;
-	}
-	switch(chan->l3prot) {
-		case ISDN_PROTO_L3_FCLASS2:
-#ifdef CONFIG_ISDN_TTY_FAX
-			reqbuf->XBuffer.P[l++] = 6;
-			reqbuf->XBuffer.P[l++] = NLC;
-			tmp = idi_fill_in_T30(chan, &reqbuf->XBuffer.P[l+1]);
-			reqbuf->XBuffer.P[l++] = tmp; 
-			l += tmp;
-			break;
-#endif
-		case ISDN_PROTO_L3_TRANS:
-		default:
-			reqbuf->XBuffer.P[l++] = 4;
-	}
-        /* Additional DLC element */
-       switch(chan->l2prot) {
-               case ISDN_PROTO_L2_X75I:
-               case ISDN_PROTO_L2_X75UI:
-               case ISDN_PROTO_L2_X75BUI:
-               case ISDN_PROTO_L2_FAX:
-                    reqbuf->XBuffer.P[l++] = DLC;
-                    reqbuf->XBuffer.P[l++] = 2;
-                    reqbuf->XBuffer.P[l++] = (2138 % 256); /* max. info (lo byte) */
-                    reqbuf->XBuffer.P[l++] = (2138 / 256); /* max. info (hi byte) */
-                break;
-        }
-	reqbuf->XBuffer.P[l++] = 0; /* end */
-	reqbuf->Req = ASSIGN;
-	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = NL_ID;
-	reqbuf->XBuffer.length = l;
-	reqbuf->Reference = 1; /* Net Entity */
-  }
-   return(0);
-}
-
-static int
-idi_put_req(eicon_REQ *reqbuf, int rq, int signet, int Ch)
-{
-	reqbuf->Req = rq;
-	reqbuf->ReqCh = Ch;
-	reqbuf->ReqId = 1;
-	reqbuf->XBuffer.length = 1;
-	reqbuf->XBuffer.P[0] = 0;
-	reqbuf->Reference = signet;
-   return(0);
-}
-
-static int
-idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan)
-{
-	reqbuf->Req = SUSPEND;
-	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = 1;
-	reqbuf->XBuffer.P[0] = CAI;
-	reqbuf->XBuffer.P[1] = 1;
-	reqbuf->XBuffer.P[2] = chan->No;
-	reqbuf->XBuffer.P[3] = 0;
-	reqbuf->XBuffer.length = 4;
-	reqbuf->Reference = 0; /* Sig Entity */
-   return(0);
-}
-
-static int
-idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
-{
-	int l = 9;
-	reqbuf->Req = CALL_RES;
-	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = 1;
-	reqbuf->XBuffer.P[0] = CAI;
-	reqbuf->XBuffer.P[1] = 6;
-	reqbuf->XBuffer.P[2] = 9;
-	reqbuf->XBuffer.P[3] = 0;
-	reqbuf->XBuffer.P[4] = 0;
-	reqbuf->XBuffer.P[5] = 0;
-	reqbuf->XBuffer.P[6] = 32;
-	reqbuf->XBuffer.P[7] = 0;
-	switch(chan->l2prot) {
-		case ISDN_PROTO_L2_X75I:
-		case ISDN_PROTO_L2_X75UI:
-		case ISDN_PROTO_L2_X75BUI:
-		case ISDN_PROTO_L2_HDLC:
-			reqbuf->XBuffer.P[1] = 1;
-			reqbuf->XBuffer.P[2] = 0x05;
-			l = 4;
-			break;
-		case ISDN_PROTO_L2_V11096:
-			reqbuf->XBuffer.P[2] = 0x0d;
-			reqbuf->XBuffer.P[3] = 5;
-			reqbuf->XBuffer.P[4] = 0;
-			break;
-		case ISDN_PROTO_L2_V11019:
-			reqbuf->XBuffer.P[2] = 0x0d;
-			reqbuf->XBuffer.P[3] = 6;
-			reqbuf->XBuffer.P[4] = 0;
-			break;
-		case ISDN_PROTO_L2_V11038:
-			reqbuf->XBuffer.P[2] = 0x0d;
-			reqbuf->XBuffer.P[3] = 7;
-			reqbuf->XBuffer.P[4] = 0;
-			break;
-		case ISDN_PROTO_L2_MODEM:
-			/* reqbuf->XBuffer.P[1] = 12; */
-			reqbuf->XBuffer.P[2] = 0x11;
-			reqbuf->XBuffer.P[3] = 9;
-			reqbuf->XBuffer.P[4] = 0;
-			reqbuf->XBuffer.P[5] = 0;
-			reqbuf->XBuffer.P[6] = 32;
-			reqbuf->XBuffer.P[7] = 0;
-			break;
-		case ISDN_PROTO_L2_FAX:
-			reqbuf->XBuffer.P[2] = 0x10;
-			reqbuf->XBuffer.P[3] = 0;
-			reqbuf->XBuffer.P[4] = 0;
-			reqbuf->XBuffer.P[5] = 0;
-			reqbuf->XBuffer.P[6] = 32;
-			reqbuf->XBuffer.P[7] = 0;
-			break;
-		case ISDN_PROTO_L2_TRANS:
-			switch(chan->l3prot) {
-				case ISDN_PROTO_L3_TRANSDSP:
-					reqbuf->XBuffer.P[2] = 22; /* DTMF, audio events on */
-			}
-			break;
-	}
-	reqbuf->XBuffer.P[l-1] = 0;
-	reqbuf->XBuffer.length = l;
-	reqbuf->Reference = 0; /* Sig Entity */
-	eicon_log(NULL, 8, "idi_req: Ch%d: Call_Res\n", chan->No);
-   return(0);
-}
-
-int
-idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer)
-{
-        struct sk_buff *skb;
-        struct sk_buff *skb2;
-	eicon_REQ *reqbuf;
-	eicon_chan_ptr *chan2;
-
-        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
-        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
-
-        if ((!skb) || (!skb2)) {
-               	eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in do_req()\n", chan->No);
-		if (skb) 
-			dev_kfree_skb(skb);
-		if (skb2) 
-			dev_kfree_skb(skb2);
-                return -ENOMEM; 
-	}
-
-	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
-	chan2->ptr = chan;
-
-	reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
-	eicon_log(card, 8, "idi_req: Ch%d: req %x (%s)\n", chan->No, cmd, (layer)?"Net":"Sig");
-	if (layer) cmd |= 0x700;
-	switch(cmd) {
-		case ASSIGN:
-		case ASSIGN|0x700:
-			idi_assign_req(reqbuf, layer, chan);
-			break;
-		case REMOVE:
-		case REMOVE|0x700:
-			idi_put_req(reqbuf, REMOVE, layer, 0);
-			break;
-		case INDICATE_REQ:
-			idi_put_req(reqbuf, INDICATE_REQ, 0, 0);
-			break;
-		case HANGUP:
-			idi_put_req(reqbuf, HANGUP, 0, 0);
-			break;
-		case SUSPEND:
-			idi_put_suspend_req(reqbuf, chan);
-			break;
-		case RESUME:
-			idi_put_req(reqbuf, RESUME, 0 ,0);
-			break;
-		case REJECT:
-			idi_put_req(reqbuf, REJECT, 0 ,0);
-			break;
-		case CALL_ALERT:
-			idi_put_req(reqbuf, CALL_ALERT, 0, 0);
-			break;
-		case CALL_RES:
-			idi_call_res_req(reqbuf, chan);
-			break;
-		case CALL_HOLD:
-			idi_put_req(reqbuf, CALL_HOLD, 0, 0);
-			break;
-		case N_CONNECT|0x700:
-			idi_put_req(reqbuf, N_CONNECT, 1, 0);
-			break;
-		case N_CONNECT_ACK|0x700:
-			idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0);
-			break;
-		case N_DISC|0x700:
-			idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh);
-			break;
-		case N_DISC_ACK|0x700:
-			idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh);
-			break;
-		default:
-			eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
-			dev_kfree_skb(skb);
-			dev_kfree_skb(skb2);
-			return(-1);
-	}
-
-	skb_queue_tail(&chan->e.X, skb);
-	skb_queue_tail(&card->sndq, skb2); 
-	eicon_tx_request(card);
-	return(0);
-}
-
-int
-eicon_idi_listen_req(eicon_card *card, eicon_chan *chan)
-{
-	if ((!card) || (!chan))
-		return 1;
-
-	eicon_log(card, 16, "idi_req: Ch%d: Listen_Req eazmask=0x%x\n",chan->No, chan->eazmask);
-	if (!chan->e.D3Id) {
-		idi_do_req(card, chan, ASSIGN, 0); 
-	}
-	if (chan->fsm_state == EICON_STATE_NULL) {
-		if (!(chan->statectrl & HAVE_CONN_REQ)) {
-			idi_do_req(card, chan, INDICATE_REQ, 0);
-			chan->fsm_state = EICON_STATE_LISTEN;
-		}
-	}
-  return(0);
-}
-
-static unsigned char
-idi_si2bc(int si1, int si2, char *bc, char *hlc)
-{
-  hlc[0] = 0;
-  switch(si1) {
-	case 1:
-		bc[0] = 0x90;		/* 3,1 kHz audio */
-		bc[1] = 0x90;		/* 64 kbit/s */
-		bc[2] = 0xa3;		/* G.711 A-law */
-#ifdef EICON_FULL_SERVICE_OKTETT
-		if (si2 == 1) {
-			bc[0] = 0x80;	/* Speech */
-			hlc[0] = 0x02;	/* hlc len */
-			hlc[1] = 0x91;	/* first hic */
-			hlc[2] = 0x81;	/* Telephony */
-		}
-#endif
-		return(3);
-	case 2:
-		bc[0] = 0x90;		/* 3,1 kHz audio */
-		bc[1] = 0x90;		/* 64 kbit/s */
-		bc[2] = 0xa3;		/* G.711 A-law */
-#ifdef EICON_FULL_SERVICE_OKTETT
-		if (si2 == 2) {
-			hlc[0] = 0x02;	/* hlc len */
-			hlc[1] = 0x91;	/* first hic */
-			hlc[2] = 0x84;	/* Fax Gr.2/3 */
-		}
-#endif
-		return(3);
-	case 5:
-	case 7:
-	default:
-		bc[0] = 0x88;
-		bc[1] = 0x90;
-		return(2);
-  }
- return (0);
-}
-
-int
-idi_hangup(eicon_card *card, eicon_chan *chan)
-{
-	if ((!card) || (!chan))
-		return 1;
-
-	if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
-	    (chan->fsm_state == EICON_STATE_WMCONN)) {
-  		if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1);
-	}
-	if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
-	if (chan->fsm_state != EICON_STATE_NULL) {
-		chan->statectrl |= WAITING_FOR_HANGUP;
-		idi_do_req(card, chan, HANGUP, 0);
-		chan->fsm_state = EICON_STATE_NULL;
-	}
-	eicon_log(card, 8, "idi_req: Ch%d: Hangup\n", chan->No);
-#ifdef CONFIG_ISDN_TTY_FAX
-	chan->fax = 0;
-#endif
-  return(0);
-}
-
-int
-capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm)
-{
-	if ((cm->para[0] != 3) || (cm->para[1] != 0))
-		return -1;
-	if (cm->para[2] < 3)
-		return -1;
-	if (cm->para[4] != 0)
-		return -1;
-	switch(cm->para[3]) {
-		case 4: /* Suspend */
-			eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No);
-			if (cm->para[5]) {
-				idi_do_req(card, chan, SUSPEND, 0);
-			} else {
-				idi_do_req(card, chan, CALL_HOLD, 0);
-			}
-			break;
-		case 5: /* Resume */
-			eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No);
-			idi_do_req(card, chan, RESUME, 0);
-			break;
-        }
-	return 0;
-}
-
-int
-idi_connect_res(eicon_card *card, eicon_chan *chan)
-{
-	if ((!card) || (!chan))
-		return 1;
-
-	chan->fsm_state = EICON_STATE_IWAIT;
-	
-	/* check if old NetID has been removed */
-	if (chan->e.B2Id) {
-		eicon_log(card, 1, "idi_conn_res: Ch%d: old net_id %x still exist, removing.\n",
-			chan->No, chan->e.B2Id);
-		idi_do_req(card, chan, REMOVE, 1);
-	}
-
-	idi_do_req(card, chan, ASSIGN, 1);
-	idi_do_req(card, chan, CALL_RES, 0);
-	return(0);
-}
-
-int
-idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
-                    char *eazmsn, int si1, int si2)
-{
-	int l = 0;
-	int i;
-	unsigned char tmp;
-	unsigned char *sub, *sp;
-	unsigned char bc[5];
-	unsigned char hlc[5];
-        struct sk_buff *skb;
-        struct sk_buff *skb2;
-	eicon_REQ *reqbuf;
-	eicon_chan_ptr *chan2;
-
-	if ((!card) || (!chan))
-		return 1;
-
-        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
-        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
-
-        if ((!skb) || (!skb2)) {
-               	eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in connect_req()\n", chan->No);
-		if (skb) 
-			dev_kfree_skb(skb);
-		if (skb2) 
-			dev_kfree_skb(skb2);
-                return -ENOMEM; 
-	}
-
-	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
-	chan2->ptr = chan;
-
-	reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
-	reqbuf->Req = CALL_REQ;
-	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = 1;
-
-	sub = NULL;
-	sp = phone;
-	while (*sp) {
-		if (*sp == '.') {
-			sub = sp + 1;
-			*sp = 0;
-		} else
-			sp++;
-	}
-	reqbuf->XBuffer.P[l++] = CPN;
-	reqbuf->XBuffer.P[l++] = strlen(phone) + 1;
-	reqbuf->XBuffer.P[l++] = 0x81;
-	for(i=0; i<strlen(phone);i++) 
-		reqbuf->XBuffer.P[l++] = phone[i] & 0x7f;
-	if (sub) {
-		reqbuf->XBuffer.P[l++] = DSA;
-		reqbuf->XBuffer.P[l++] = strlen(sub) + 2;
-		reqbuf->XBuffer.P[l++] = 0x80; /* NSAP coded */
-		reqbuf->XBuffer.P[l++] = 0x50; /* local IDI format */
-		while (*sub)
-			reqbuf->XBuffer.P[l++] = *sub++ & 0x7f;
-	}
-
-	sub = NULL;
-	sp = eazmsn;
-	while (*sp) {
-		if (*sp == '.') {
-			sub = sp + 1;
-			*sp = 0;
-		} else
-			sp++;
-	}
-	reqbuf->XBuffer.P[l++] = OAD;
-	reqbuf->XBuffer.P[l++] = strlen(eazmsn) + 2;
-	reqbuf->XBuffer.P[l++] = 0x01;
-	reqbuf->XBuffer.P[l++] = 0x80;
-	for(i=0; i<strlen(eazmsn);i++) 
-		reqbuf->XBuffer.P[l++] = eazmsn[i] & 0x7f;
-	if (sub) {
-		reqbuf->XBuffer.P[l++] = OSA;
-		reqbuf->XBuffer.P[l++] = strlen(sub) + 2;
-		reqbuf->XBuffer.P[l++] = 0x80; /* NSAP coded */
-		reqbuf->XBuffer.P[l++] = 0x50; /* local IDI format */
-		while (*sub)
-			reqbuf->XBuffer.P[l++] = *sub++ & 0x7f;
-	}
-
-	if (si2 > 2) {
-		reqbuf->XBuffer.P[l++] = SHIFT|6;
-		reqbuf->XBuffer.P[l++] = SIN;
-		reqbuf->XBuffer.P[l++] = 2;
-		reqbuf->XBuffer.P[l++] = si1;
-		reqbuf->XBuffer.P[l++] = si2;
-	}
-	else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
-		reqbuf->XBuffer.P[l++] = BC;
-		reqbuf->XBuffer.P[l++] = tmp;
-		for(i=0; i<tmp;i++) 
-			reqbuf->XBuffer.P[l++] = bc[i];
-		if ((tmp=hlc[0])) {
-			reqbuf->XBuffer.P[l++] = HLC;
-			reqbuf->XBuffer.P[l++] = tmp;
-			for(i=1; i<=tmp;i++) 
-				reqbuf->XBuffer.P[l++] = hlc[i];
-		}
-	}
-
-        reqbuf->XBuffer.P[l++] = CAI;
-        reqbuf->XBuffer.P[l++] = 6;
-        reqbuf->XBuffer.P[l++] = 0x09;
-	reqbuf->XBuffer.P[l++] = 0;
-	reqbuf->XBuffer.P[l++] = 0;
-	reqbuf->XBuffer.P[l++] = 0;
-	reqbuf->XBuffer.P[l++] = 32;
-	reqbuf->XBuffer.P[l++] = 0;
-        switch(chan->l2prot) {
-		case ISDN_PROTO_L2_X75I:
-		case ISDN_PROTO_L2_X75UI:
-		case ISDN_PROTO_L2_X75BUI:
-                case ISDN_PROTO_L2_HDLC:
-                        reqbuf->XBuffer.P[l-6] = 5;
-                        reqbuf->XBuffer.P[l-7] = 1;
-			l -= 5; 
-                        break;
-                case ISDN_PROTO_L2_V11096:
-                        reqbuf->XBuffer.P[l-7] = 3;
-                        reqbuf->XBuffer.P[l-6] = 0x0d;
-                        reqbuf->XBuffer.P[l-5] = 5;
-                        reqbuf->XBuffer.P[l-4] = 0;
-                        l -= 3;
-                        break;
-                case ISDN_PROTO_L2_V11019:
-                        reqbuf->XBuffer.P[l-7] = 3;
-                        reqbuf->XBuffer.P[l-6] = 0x0d;
-                        reqbuf->XBuffer.P[l-5] = 6;
-                        reqbuf->XBuffer.P[l-4] = 0;
-                        l -= 3;
-                        break;
-                case ISDN_PROTO_L2_V11038:
-                        reqbuf->XBuffer.P[l-7] = 3;
-                        reqbuf->XBuffer.P[l-6] = 0x0d;
-                        reqbuf->XBuffer.P[l-5] = 7;
-                        reqbuf->XBuffer.P[l-4] = 0;
-                        l -= 3;
-                        break;
-                case ISDN_PROTO_L2_MODEM:
-			/* reqbuf->XBuffer.P[l-7] = 12; */
-			reqbuf->XBuffer.P[l-6] = 0x11;
-			reqbuf->XBuffer.P[l-5] = 7;
-			reqbuf->XBuffer.P[l-4] = 0;
-			reqbuf->XBuffer.P[l-3] = 0;
-			reqbuf->XBuffer.P[l-2] = 32;
-			reqbuf->XBuffer.P[l-1] = 0;
-                        break;
-                case ISDN_PROTO_L2_FAX:
-			reqbuf->XBuffer.P[l-6] = 0x10;
-			reqbuf->XBuffer.P[l-5] = 0;
-			reqbuf->XBuffer.P[l-4] = 0;
-			reqbuf->XBuffer.P[l-3] = 0;
-			reqbuf->XBuffer.P[l-2] = 32;
-			reqbuf->XBuffer.P[l-1] = 0;
-                        break;
-		case ISDN_PROTO_L2_TRANS:
-			switch(chan->l3prot) {
-				case ISDN_PROTO_L3_TRANSDSP:
-					reqbuf->XBuffer.P[l-6] = 22; /* DTMF, audio events on */
-			}
-			break;
-        }
-	
-	reqbuf->XBuffer.P[l++] = 0; /* end */
-	reqbuf->XBuffer.length = l;
-	reqbuf->Reference = 0; /* Sig Entity */
-
-	if (chan->statectrl & WAITING_FOR_HANGUP) {
-		/*	If the line did not disconnect yet,
-			we have to delay this command		*/
-		eicon_log(card, 32, "idi_req: Ch%d: delaying conn_req\n", chan->No);
-		chan->statectrl |= HAVE_CONN_REQ;
-		chan->tskb1 = skb;
-		chan->tskb2 = skb2;
-	} else {
-		skb_queue_tail(&chan->e.X, skb);
-		skb_queue_tail(&card->sndq, skb2); 
-		eicon_tx_request(card);
-	}
-
-	eicon_log(card, 8, "idi_req: Ch%d: Conn_Req %s -> %s\n",chan->No, eazmsn, phone);
-   return(0);
-}
-
-
-static void
-idi_IndParse(eicon_card *ccard, eicon_chan *chan, idi_ind_message *message, unsigned char *buffer, int len)
-{
-	int i,j;
-	int pos = 0;
-	int codeset = 0;
-	int wlen = 0;
-	int lock = 0;
-	__u8 w;
-	__u16 code;
-	isdn_ctrl cmd;
-
-	memset(message, 0, sizeof(idi_ind_message));
-
-	if ((!len) || (!buffer[pos])) return;
-
-  while(pos <= len) {
-	w = buffer[pos++];
-	if (!w) return;
-	if (w & 0x80) {
-		wlen = 0;
-	}
-	else {
-		wlen = buffer[pos++];
-	}
-
-	if (pos > len) return;
-
-	if (lock & 0x80) lock &= 0x7f;
-	else codeset = lock;
-
-	if((w&0xf0) == SHIFT) {
-		codeset = w;
-		if(!(codeset & 0x08)) lock = codeset & 7;
-		codeset &= 7;
-		lock |= 0x80;
-	}
-	else {
-		if (w==ESC && wlen >=2) {
-			code = buffer[pos++]|0x800;
-			wlen--;
-		}
-		else code = w;
-		code |= (codeset<<8);
-
-		if (pos + wlen > len) {
-			eicon_log(ccard, 1, "idi_err: Ch%d: IElen %d of %x exceeds Ind_Length (+%d)\n", chan->No, 
-					wlen, code, (pos + wlen) - len);
-			return;
-		}
-
-		switch(code) {
-			case OAD:
-				if (wlen > sizeof(message->oad)) {
-					pos += wlen;
-					break;
-				}
-				j = 1;
-				if (wlen) {
-					message->plan = buffer[pos++];
-					if (message->plan &0x80) 
-						message->screen = 0;
-					else {
-						message->screen = buffer[pos++];
-						j = 2;
-					}
-				}
-				for(i=0; i < wlen-j; i++) 
-					message->oad[i] = buffer[pos++];
-				eicon_log(ccard, 2, "idi_inf: Ch%d: OAD=(0x%02x,0x%02x) %s\n", chan->No, 
-					message->plan, message->screen, message->oad);
-				break;
-			case RDN:
-				if (wlen > sizeof(message->rdn)) {
-					pos += wlen;
-					break;
-				}
-				j = 1;
-				if (wlen) {
-					if (!(buffer[pos++] & 0x80)) {
-						pos++; 
-						j = 2;
-					}
-				}
-				for(i=0; i < wlen-j; i++) 
-					message->rdn[i] = buffer[pos++];
-				eicon_log(ccard, 2, "idi_inf: Ch%d: RDN= %s\n", chan->No, 
-						message->rdn);
-				break;
-			case CPN:
-				if (wlen > sizeof(message->cpn)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->cpn[i] = buffer[pos++];
-				eicon_log(ccard, 2, "idi_inf: Ch%d: CPN=(0x%02x) %s\n", chan->No,
-					(__u8)message->cpn[0], message->cpn + 1);
-				break;
-			case DSA:
-				if (wlen > sizeof(message->dsa)) {
-					pos += wlen;
-					break;
-				}
-				pos += 2;
-				for(i=0; i < wlen-2; i++) 
-					message->dsa[i] = buffer[pos++];
-				eicon_log(ccard, 2, "idi_inf: Ch%d: DSA=%s\n", chan->No, message->dsa);
-				break;
-			case OSA:
-				if (wlen > sizeof(message->osa)) {
-					pos += wlen;
-					break;
-				}
-				pos += 2;
-				for(i=0; i < wlen-2; i++) 
-					message->osa[i] = buffer[pos++];
-				eicon_log(ccard, 2, "idi_inf: Ch%d: OSA=%s\n", chan->No, message->osa);
-				break;
-			case CAD:
-				pos += wlen;
-				eicon_log(ccard, 2, "idi_inf: Ch%d: Connected Address in ind, len:%x\n", 
-					chan->No, wlen);
-				break;
-			case BC:
-				if (wlen > sizeof(message->bc)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->bc[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: BC = 0x%02x 0x%02x 0x%02x\n", chan->No,
-					message->bc[0],message->bc[1],message->bc[2]);
-				break;
-			case 0x800|BC:
-				if (wlen > sizeof(message->e_bc)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->e_bc[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/BC=%d\n", chan->No, message->bc[0]);
-				break;
-			case LLC:
-				if (wlen > sizeof(message->llc)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->llc[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0],
-					message->llc[1],message->llc[2],message->llc[3]);
-				break;
-			case HLC:
-				if (wlen > sizeof(message->hlc)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->hlc[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No,
-					message->hlc[0], message->hlc[1],
-					message->hlc[2], message->hlc[3], message->hlc[4]);
-				break;
-			case DSP:
-			case 0x600|DSP:
-				if (wlen > sizeof(message->display)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->display[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: Display: %s\n", chan->No,
-					message->display);
-				break;
-			case 0x600|KEY:
-				if (wlen > sizeof(message->keypad)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->keypad[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: Keypad: %s\n", chan->No,
-					message->keypad);
-				break;
-			case NI:
-			case 0x600|NI:
-				if (wlen) {
-					switch(buffer[pos] & 127) {
-						case 0:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: User suspended.\n", chan->No);
-							break;
-						case 1:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: User resumed.\n", chan->No);
-							break;
-						case 2:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: Bearer service change.\n", chan->No);
-							break;
-						default:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Notification %x.\n", 
-									chan->No, buffer[pos] & 127);
-					}
-					pos += wlen;
-				}
-				break;
-			case PI:
-			case 0x600|PI:
-				if (wlen > 1) {
-					switch(buffer[pos+1] & 127) {
-						case 1:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: Call is not end-to-end ISDN.\n", chan->No);
-							break;
-						case 2:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: Destination address is non ISDN.\n", chan->No);
-							break;
-						case 3:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: Origination address is non ISDN.\n", chan->No);
-							break;
-						case 4:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: Call has returned to the ISDN.\n", chan->No);
-							break;
-						case 5:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: Interworking has occurred.\n", chan->No);
-							break;
-						case 8:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: In-band information available.\n", chan->No);
-							break;
-						default:
-							eicon_log(ccard, 4, "idi_inf: Ch%d: Unknown Progress %x.\n", 
-									chan->No, buffer[pos+1] & 127);
-					}
-				}
-				pos += wlen;
-				break;
-			case CAU:
-				if (wlen > sizeof(message->cau)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->cau[i] = buffer[pos++];
-				memcpy(&chan->cause, &message->cau, 2);
-				eicon_log(ccard, 4, "idi_inf: Ch%d: CAU=%d %d\n", chan->No,
-					message->cau[0],message->cau[1]);
-				break;
-			case 0x800|CAU:
-				if (wlen > sizeof(message->e_cau)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->e_cau[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: ECAU=%d %d\n", chan->No,
-					message->e_cau[0],message->e_cau[1]);
-				break;
-			case 0x800|CHI:
-				if (wlen > sizeof(message->e_chi)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->e_chi[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: ESC/CHI=%d\n", chan->No,
-					message->e_cau[0]);
-				break;
-			case 0x800|0x7a:
-				pos ++;
-				message->e_mt=buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: EMT=0x%x\n", chan->No, message->e_mt);
-				break;
-			case DT:
-				if (wlen > sizeof(message->dt)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->dt[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: DT: %02d.%02d.%02d %02d:%02d:%02d\n", chan->No,
-					message->dt[2], message->dt[1], message->dt[0],
-					message->dt[3], message->dt[4], message->dt[5]);
-				break;
-			case 0x600|SIN:
-				if (wlen > sizeof(message->sin)) {
-					pos += wlen;
-					break;
-				}
-				for(i=0; i < wlen; i++) 
-					message->sin[i] = buffer[pos++];
-				eicon_log(ccard, 2, "idi_inf: Ch%d: SIN=%d %d\n", chan->No,
-					message->sin[0],message->sin[1]);
-				break;
-			case 0x600|CPS:
-				eicon_log(ccard, 2, "idi_inf: Ch%d: Called Party Status in ind\n", chan->No);
-				pos += wlen;
-				break;
-			case 0x600|CIF:
-				for (i = 0; i < wlen; i++)
-					if (buffer[pos + i] != '0') break;
-				memcpy(&cmd.parm.num, &buffer[pos + i], wlen - i);
-				cmd.parm.num[wlen - i] = 0;
-				eicon_log(ccard, 2, "idi_inf: Ch%d: CIF=%s\n", chan->No, cmd.parm.num);
-				pos += wlen;
-				cmd.driver = ccard->myid;
-				cmd.command = ISDN_STAT_CINF;
-				cmd.arg = chan->No;
-				ccard->interface.statcallb(&cmd);
-				break;
-			case 0x600|DATE:
-				eicon_log(ccard, 2, "idi_inf: Ch%d: Date in ind\n", chan->No);
-				pos += wlen;
-				break;
-			case 0xa1: 
-				eicon_log(ccard, 2, "idi_inf: Ch%d: Sending Complete in ind.\n", chan->No);
-				pos += wlen;
-				break;
-			case 0xe08: 
-			case 0xe7a: 
-			case 0xe04: 
-			case 0xe00: 
-				/* *** TODO *** */
-			case CHA:
-				/* Charge advice */
-			case FTY:
-			case 0x600|FTY:
-			case CHI:
-			case 0x800:
-				/* Not yet interested in this */
-				pos += wlen;
-				break;
-			case 0x880:
-				/* Managment Information Element */
-				if (!manbuf) {
-					eicon_log(ccard, 1, "idi_err: manbuf not allocated\n");
-				}
-				else {
-					memcpy(&manbuf->data[manbuf->pos], &buffer[pos], wlen);
-					manbuf->length[manbuf->count] = wlen;
-					manbuf->count++;
-					manbuf->pos += wlen;
-				}
-				pos += wlen;
-				break;
-			default:
-				pos += wlen;
-				eicon_log(ccard, 6, "idi_inf: Ch%d: unknown information element 0x%x in ind, len:%x\n", 
-					chan->No, code, wlen);
-		}
-	}
-  }
-}
-
-static void
-idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2)
-{
-	si1[0] = 0;
-	si2[0] = 0;
-
-	switch (bc[0] & 0x7f) {
-		case 0x00: /* Speech */
-			si1[0] = 1;
-#ifdef EICON_FULL_SERVICE_OKTETT
-			si1[0] = sin[0];
-			si2[0] = sin[1];
-#endif
-			break;
-		case 0x10: /* 3.1 Khz audio */
-			si1[0] = 1;
-#ifdef EICON_FULL_SERVICE_OKTETT
-			si1[0] = sin[0];
-			si2[0] = sin[1];
-#endif
-			break;
-		case 0x08: /* Unrestricted digital information */
-			si1[0] = 7;
-			si2[0] = sin[1];
-			break;
-		case 0x09: /* Restricted digital information */
-			si1[0] = 2;
-			break;
-		case 0x11:
-			/* Unrestr. digital information  with
-			 * tones/announcements ( or 7 kHz audio
-			 */
-			si1[0] = 3;
-			break;
-		case 0x18: /* Video */
-			si1[0] = 4;
-			break;
-	}
-	switch (bc[1] & 0x7f) {
-		case 0x40: /* packed mode */
-			si1[0] = 8;
-			break;
-		case 0x10: /* 64 kbit */
-		case 0x11: /* 2*64 kbit */
-		case 0x13: /* 384 kbit */
-		case 0x15: /* 1536 kbit */
-		case 0x17: /* 1920 kbit */
-			/* moderate = bc[1] & 0x7f; */
-			break;
-	}
-}
-
-/********************* FAX stuff ***************************/
-
-#ifdef CONFIG_ISDN_TTY_FAX
-
-static int
-idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer)
-{
-	eicon_t30_s	*t30 = (eicon_t30_s *) buffer;
-
-	if (!chan->fax) {
-		eicon_log(NULL, 1,"idi_T30: fill_in with NULL fax struct, ERROR\n");
-		return 0;
-	}
-	memset(t30, 0, sizeof(eicon_t30_s));
-	t30->station_id_len = EICON_FAXID_LEN;
-	memcpy(&t30->station_id[0], &chan->fax->id[0], EICON_FAXID_LEN);
-	t30->resolution = chan->fax->resolution;
-	t30->rate = chan->fax->rate + 1;	/* eicon rate starts with 1 */
-	t30->format = T30_FORMAT_SFF;
-	t30->pages_low = 0;
-	t30->pages_high = 0;
-	t30->atf = 1;				/* optimised for AT+F command set */
-	t30->code = 0;
-	t30->feature_bits_low = 0;
-	t30->feature_bits_high = 0;
-	t30->control_bits_low = 0;
-	t30->control_bits_high = 0;
-
-	if (chan->fax->nbc) {
-		/* set compression by DCC value */
-  	  switch(chan->fax->compression) {
-		case (0):	/* 1-D modified */
-			break;
-		case (1):	/* 2-D modified Read */
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
-			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
-			break;
-		case (2):	/* 2-D uncompressed */
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
-			t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
-			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
-			break;
-		case (3):	/* 2-D modified Read */
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
-			t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
-			t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
-			t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
-			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
-			break;
-	  }
-	} else {
-		/* set compression to best */
-		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_T6_CODING;
-		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_2D_CODING;
-		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_UNCOMPR;
-		t30->feature_bits_low |= T30_FEATURE_BIT_UNCOMPR_ENABLED;
-		t30->feature_bits_low |= T30_FEATURE_BIT_T6_CODING;
-		t30->feature_bits_low |= T30_FEATURE_BIT_2D_CODING;
-		t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
-		t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
-	}
-	switch(chan->fax->ecm) {
-		case (0):	/* disable ECM */
-			break;
-		case (1):
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
-			t30->control_bits_low |= T30_CONTROL_BIT_ECM_64_BYTES;
-			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
-			t30->feature_bits_low |= T30_FEATURE_BIT_ECM_64_BYTES;
-			break;
-		case (2):
-			t30->control_bits_low |= T30_CONTROL_BIT_ENABLE_ECM;
-			t30->feature_bits_low |= T30_FEATURE_BIT_ECM;
-			break;
-	}
-
-	if (DebugVar & 128) {
-		char st[40];
-		eicon_log(NULL, 128, "sT30:code = %x\n", t30->code);
-		eicon_log(NULL, 128, "sT30:rate = %x\n", t30->rate);
-		eicon_log(NULL, 128, "sT30:res  = %x\n", t30->resolution);
-		eicon_log(NULL, 128, "sT30:format = %x\n", t30->format);
-		eicon_log(NULL, 128, "sT30:pages_low = %x\n", t30->pages_low);
-		eicon_log(NULL, 128, "sT30:pages_high = %x\n", t30->pages_high);
-		eicon_log(NULL, 128, "sT30:atf  = %x\n", t30->atf);
-		eicon_log(NULL, 128, "sT30:control_bits_low = %x\n", t30->control_bits_low);
-		eicon_log(NULL, 128, "sT30:control_bits_high = %x\n", t30->control_bits_high);
-		eicon_log(NULL, 128, "sT30:feature_bits_low = %x\n", t30->feature_bits_low);
-		eicon_log(NULL, 128, "sT30:feature_bits_high = %x\n", t30->feature_bits_high);
-		//eicon_log(NULL, 128, "sT30:universal_5 = %x\n", t30->universal_5);
-		//eicon_log(NULL, 128, "sT30:universal_6 = %x\n", t30->universal_6);
-		//eicon_log(NULL, 128, "sT30:universal_7 = %x\n", t30->universal_7);
-		eicon_log(NULL, 128, "sT30:station_id_len = %x\n", t30->station_id_len);
-		eicon_log(NULL, 128, "sT30:head_line_len = %x\n", t30->head_line_len);
-		strlcpy(st, t30->station_id, t30->station_id_len + 1);
-		eicon_log(NULL, 128, "sT30:station_id = <%s>\n", st);
-	}
-	return(sizeof(eicon_t30_s));
-}
-
-/* send fax struct */
-static int
-idi_send_edata(eicon_card *card, eicon_chan *chan)
-{
-	struct sk_buff *skb;
-	struct sk_buff *skb2;
-	eicon_REQ *reqbuf;
-	eicon_chan_ptr *chan2;
-
-	if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
-		eicon_log(card, 1, "idi_snd: Ch%d: send edata on state %d !\n", chan->No, chan->fsm_state);
-		return -ENODEV;
-	}
-	eicon_log(card, 128, "idi_snd: Ch%d: edata (fax)\n", chan->No);
-
-	skb = alloc_skb(sizeof(eicon_REQ) + sizeof(eicon_t30_s), GFP_ATOMIC);
-	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
-
-	if ((!skb) || (!skb2)) {
-		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_edata()\n", chan->No);
-		if (skb) 
-			dev_kfree_skb(skb);
-		if (skb2) 
-			dev_kfree_skb(skb2);
-		return -ENOMEM;
-	}
-
-	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
-	chan2->ptr = chan;
-
-	reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
-
-	reqbuf->Req = N_EDATA;
-	reqbuf->ReqCh = chan->e.IndCh;
-	reqbuf->ReqId = 1;
-
-	reqbuf->XBuffer.length = idi_fill_in_T30(chan, reqbuf->XBuffer.P);
-	reqbuf->Reference = 1; /* Net Entity */
-
-	skb_queue_tail(&chan->e.X, skb);
-	skb_queue_tail(&card->sndq, skb2);
-	eicon_tx_request(card);
-	return (0);
-}
-
-static void
-idi_parse_edata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
-{
-	eicon_t30_s *p = (eicon_t30_s *)buffer;
-	int i;
-
-	if (DebugVar & 128) {
-		char st[40];
-		eicon_log(ccard, 128, "rT30:len %d , size %d\n", len, sizeof(eicon_t30_s));
-		eicon_log(ccard, 128, "rT30:code = %x\n", p->code);
-		eicon_log(ccard, 128, "rT30:rate = %x\n", p->rate);
-		eicon_log(ccard, 128, "rT30:res  = %x\n", p->resolution);
-		eicon_log(ccard, 128, "rT30:format = %x\n", p->format);
-		eicon_log(ccard, 128, "rT30:pages_low = %x\n", p->pages_low);
-		eicon_log(ccard, 128, "rT30:pages_high = %x\n", p->pages_high);
-		eicon_log(ccard, 128, "rT30:atf  = %x\n", p->atf);
-		eicon_log(ccard, 128, "rT30:control_bits_low = %x\n", p->control_bits_low);
-		eicon_log(ccard, 128, "rT30:control_bits_high = %x\n", p->control_bits_high);
-		eicon_log(ccard, 128, "rT30:feature_bits_low = %x\n", p->feature_bits_low);
-		eicon_log(ccard, 128, "rT30:feature_bits_high = %x\n", p->feature_bits_high);
-		//eicon_log(ccard, 128, "rT30:universal_5 = %x\n", p->universal_5);
-		//eicon_log(ccard, 128, "rT30:universal_6 = %x\n", p->universal_6);
-		//eicon_log(ccard, 128, "rT30:universal_7 = %x\n", p->universal_7);
-		eicon_log(ccard, 128, "rT30:station_id_len = %x\n", p->station_id_len);
-		eicon_log(ccard, 128, "rT30:head_line_len = %x\n", p->head_line_len);
-		strlcpy(st, p->station_id, p->station_id_len + 1);
-		eicon_log(ccard, 128, "rT30:station_id = <%s>\n", st);
-	}
-	if (!chan->fax) {
-		eicon_log(ccard, 1, "idi_edata: parse to NULL fax struct, ERROR\n");
-		return;
-	}
-	chan->fax->code = p->code;
-	i = (p->station_id_len < FAXIDLEN) ? p->station_id_len : (FAXIDLEN - 1);
-	memcpy(chan->fax->r_id, p->station_id, i);
-	chan->fax->r_id[i] = 0;
-	chan->fax->r_resolution = p->resolution;
-	chan->fax->r_rate = p->rate - 1;
-	chan->fax->r_binary = 0; /* no binary support */
-	chan->fax->r_width = 0;
-	chan->fax->r_length = 2;
-	chan->fax->r_scantime = 0;
-	chan->fax->r_compression = 0;
-	chan->fax->r_ecm = 0;
-	if (p->feature_bits_low & T30_FEATURE_BIT_2D_CODING) {
-		chan->fax->r_compression = 1;
-		if (p->feature_bits_low & T30_FEATURE_BIT_UNCOMPR_ENABLED) {
-			chan->fax->r_compression = 2;
-		}
-	}
-	if (p->feature_bits_low & T30_FEATURE_BIT_T6_CODING) {
-		chan->fax->r_compression = 3;
-	}
-
-	if (p->feature_bits_low & T30_FEATURE_BIT_ECM) {
-		chan->fax->r_ecm = 2;
-		if (p->feature_bits_low & T30_FEATURE_BIT_ECM_64_BYTES)
-			chan->fax->r_ecm = 1;
-	}
-}
-
-static void
-idi_fax_send_header(eicon_card *card, eicon_chan *chan, int header)
-{
-	static __u16 wd2sff[] = {
-		1728, 2048, 2432, 1216, 864
-	};
-	static __u16 ln2sff[2][3] = {
-		{ 1143, 1401, 0 } , { 2287, 2802, 0 }
-	};
-	struct sk_buff *skb;
-	eicon_sff_dochead *doc;
-	eicon_sff_pagehead *page;
-	u_char *docp;
-
-	if (!chan->fax) {
-		eicon_log(card, 1, "idi_fax: send head with NULL fax struct, ERROR\n");
-		return;
-	}
-	if (header == 2) { /* DocHeader + PageHeader */
-		skb = alloc_skb(sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead), GFP_ATOMIC);
-	} else {
-		skb = alloc_skb(sizeof(eicon_sff_pagehead), GFP_ATOMIC);
-	}
-	if (!skb) {
-		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_header()\n", chan->No);
-		return;
-	}
-
-	if (header == 2) { /* DocHeader + PageHeader */
-		docp = skb_put(skb, sizeof(eicon_sff_dochead) + sizeof(eicon_sff_pagehead));
-		doc = (eicon_sff_dochead *) docp;
-		page = (eicon_sff_pagehead *) (docp + sizeof(eicon_sff_dochead));
-		memset(docp, 0,sizeof(eicon_sff_dochead)  + sizeof(eicon_sff_pagehead));
-		doc->id = 0x66666653;
-		doc->version = 0x01;
-		doc->off1pagehead = sizeof(eicon_sff_dochead);
-	} else {
-		page = (eicon_sff_pagehead *)skb_put(skb, sizeof(eicon_sff_pagehead));
-		memset(page, 0, sizeof(eicon_sff_pagehead));
-	}
-
-	switch(header) {
-		case 1:	/* PageHeaderEnd */
-			page->pageheadid = 254;
-			page->pageheadlen = 0; 
-			break;
-		case 0: /* PageHeader */
-		case 2: /* DocHeader + PageHeader */
-			page->pageheadid = 254;
-			page->pageheadlen = sizeof(eicon_sff_pagehead) - 2;
-			page->resvert = chan->fax->resolution;
-			page->reshoriz = 0; /* always 203 dpi */
-			page->coding = 0; /* always 1D */
-			page->linelength = wd2sff[chan->fax->width];
-			page->pagelength = ln2sff[chan->fax->resolution][chan->fax->length]; 
-			eicon_log(card, 128, "sSFF-Head: linelength = %d\n", page->linelength);
-			eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength);
-			break;
-	}
-	idi_send_data(card, chan, 0, skb, 0, 0);
-}
-
-void
-idi_fax_cmd(eicon_card *card, eicon_chan *chan) 
-{
-	isdn_ctrl cmd;
-
-	if ((!card) || (!chan))
-		return;
-
-	if (!chan->fax) {
-		eicon_log(card, 1, "idi_fax: cmd with NULL fax struct, ERROR\n");
-		return;
-	}
-	switch (chan->fax->code) {
-		case ISDN_TTY_FAX_DT:
-			if (chan->fax->phase == ISDN_FAX_PHASE_B) {
-				idi_send_edata(card, chan);
-				break;
-			}
-			if (chan->fax->phase == ISDN_FAX_PHASE_D) {
-				idi_send_edata(card, chan);
-				break;
-			}
-			break;
-
-		case ISDN_TTY_FAX_DR:
-			if (chan->fax->phase == ISDN_FAX_PHASE_B) {
-				idi_send_edata(card, chan);
-
-				cmd.driver = card->myid;
-				cmd.command = ISDN_STAT_FAXIND;
-				cmd.arg = chan->No;
-				chan->fax->r_code = ISDN_TTY_FAX_CFR;
-				card->interface.statcallb(&cmd);
-
-				cmd.driver = card->myid;
-				cmd.command = ISDN_STAT_FAXIND;
-				cmd.arg = chan->No;
-				chan->fax->r_code = ISDN_TTY_FAX_RID;
-				card->interface.statcallb(&cmd);
-
-				/* telling 1-D compression */
-				chan->fax->r_compression = 0;
-				cmd.driver = card->myid;
-				cmd.command = ISDN_STAT_FAXIND;
-				cmd.arg = chan->No;
-				chan->fax->r_code = ISDN_TTY_FAX_DCS;
-				card->interface.statcallb(&cmd);
-
-				chan->fax2.NextObject = FAX_OBJECT_DOCU;
-				chan->fax2.PrevObject = FAX_OBJECT_DOCU;
-
-				break;
-			}
-			if (chan->fax->phase == ISDN_FAX_PHASE_D) {
-				idi_send_edata(card, chan);
-				break;
-			}
-			break;
-
-		case ISDN_TTY_FAX_ET:
-				switch(chan->fax->fet) {
-					case 0:
-					case 1:
-						idi_fax_send_header(card, chan, 0);
-						break;
-					case 2:
-						idi_fax_send_header(card, chan, 1);
-						break;
-				}
-			break;
-	}
-}
-
-static void
-idi_edata_rcveop(eicon_card *card, eicon_chan *chan)
-{
-	isdn_ctrl cmd;
-
-	if (!chan->fax) {
-		eicon_log(card, 1, "idi_edata: rcveop with NULL fax struct, ERROR\n");
-		return;
-	}
-	cmd.driver = card->myid;
-	cmd.command = ISDN_STAT_FAXIND;
-	cmd.arg = chan->No;
-	chan->fax->r_code = ISDN_TTY_FAX_ET;
-	card->interface.statcallb(&cmd);
-}
-
-static void
-idi_reset_fax_stat(eicon_chan *chan)
-{
-	chan->fax2.LineLen = 0;
-	chan->fax2.LineData = 0;
-	chan->fax2.LineDataLen = 0;
-	chan->fax2.NullByteExist = 0;
-	chan->fax2.Dle = 0;
-	chan->fax2.PageCount = 0;
-	chan->fax2.Eop = 0;
-}
-
-static void
-idi_edata_action(eicon_card *ccard, eicon_chan *chan, char *buffer, int len)
-{
-	isdn_ctrl cmd;
-
-	if (!chan->fax) {
-		eicon_log(ccard, 1, "idi_edata: action with NULL fax struct, ERROR\n");
-		return;
-	}
-	if (chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) {
-		idi_parse_edata(ccard, chan, buffer, len);
-
-		if (chan->fax->phase == ISDN_FAX_PHASE_A) {
-			idi_reset_fax_stat(chan);
-
-			chan->fsm_state = EICON_STATE_ACTIVE;
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_BCONN;
-			cmd.arg = chan->No;
-			strcpy(cmd.parm.num, "");
-			ccard->interface.statcallb(&cmd);
-
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_FAXIND;
-			cmd.arg = chan->No;
-			chan->fax->r_code = ISDN_TTY_FAX_FCON;
-			ccard->interface.statcallb(&cmd);
-
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_FAXIND;
-			cmd.arg = chan->No;
-			chan->fax->r_code = ISDN_TTY_FAX_RID;
-			ccard->interface.statcallb(&cmd);
-
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_FAXIND;
-			cmd.arg = chan->No;
-			chan->fax->r_code = ISDN_TTY_FAX_DIS;
-			ccard->interface.statcallb(&cmd);
-
-			if (chan->fax->r_compression != 0) {
-			/* telling fake compression in second DIS message */
-				chan->fax->r_compression = 0;
-				cmd.driver = ccard->myid;
-				cmd.command = ISDN_STAT_FAXIND;
-				cmd.arg = chan->No;
-				chan->fax->r_code = ISDN_TTY_FAX_DIS;
-				ccard->interface.statcallb(&cmd);
-			}
-
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_FAXIND;
-			cmd.arg = chan->No;
-			chan->fax->r_code = ISDN_TTY_FAX_SENT; /* OK message */
-			ccard->interface.statcallb(&cmd);
-		} else
-		if (chan->fax->phase == ISDN_FAX_PHASE_D) {
-
-			if ((chan->fax->code == EDATA_T30_MCF) &&
-			    (chan->fax->fet != 2)) {
-				cmd.driver = ccard->myid;
-				cmd.command = ISDN_STAT_FAXIND;
-				cmd.arg = chan->No;
-				chan->fax->r_code = ISDN_TTY_FAX_PTS;
-				ccard->interface.statcallb(&cmd);
-			}
-
-			switch(chan->fax->fet) {
-				case 0:	/* new page */
-					/* stay in phase D , wait on cmd +FDT */
-					break;
-				case 1:	/* new document */
-					/* link-level switch to phase B */
-					break;
-				case 2:	/* session end */
-				default:
-					/* send_edata produces error on some */
-					/* fax-machines here, so we don't */
-					/* idi_send_edata(ccard, chan); */
-					break;
-			}
-		}
-	}
-
-	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
-		idi_parse_edata(ccard, chan, buffer, len);
-
-		if ((chan->fax->code == EDATA_T30_DCS) &&
-		    (chan->fax->phase == ISDN_FAX_PHASE_A)) {
-			idi_reset_fax_stat(chan);
-
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_BCONN;
-			cmd.arg = chan->No;
-			strcpy(cmd.parm.num, "");
-			ccard->interface.statcallb(&cmd);
-
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_FAXIND;
-			cmd.arg = chan->No;
-			chan->fax->r_code = ISDN_TTY_FAX_FCON_I;
-			ccard->interface.statcallb(&cmd);
-		} else
-		if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
-		    (chan->fax->phase == ISDN_FAX_PHASE_A)) {
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_FAXIND;
-			cmd.arg = chan->No;
-			chan->fax->r_code = ISDN_TTY_FAX_RID;
-			ccard->interface.statcallb(&cmd);
-
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_FAXIND;
-			cmd.arg = chan->No;
-			chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
-			ccard->interface.statcallb(&cmd);
-		} else
-		if ((chan->fax->code == EDATA_T30_TRAIN_OK) &&
-		    (chan->fax->phase == ISDN_FAX_PHASE_B)) {
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_FAXIND;
-			cmd.arg = chan->No;
-			chan->fax->r_code = ISDN_TTY_FAX_TRAIN_OK;
-			ccard->interface.statcallb(&cmd);
-		} else
-		if (chan->fax->phase == ISDN_FAX_PHASE_C) {
-			switch(chan->fax->code) {
-				case EDATA_T30_TRAIN_OK:
-					idi_send_edata(ccard, chan);
-					break;
-				case EDATA_T30_MPS:
-					chan->fax->fet = 0;
-					idi_edata_rcveop(ccard, chan);
-					break;
-				case EDATA_T30_EOM:
-					chan->fax->fet = 1;
-					idi_edata_rcveop(ccard, chan);
-					break;
-				case EDATA_T30_EOP:
-					chan->fax->fet = 2;
-					idi_edata_rcveop(ccard, chan);
-					break;
-			}
-		}
-	}
-}
-
-static void
-fax_put_rcv(eicon_card *ccard, eicon_chan *chan, u_char *Data, int len)
-{
-	struct sk_buff *skb;
-	
-        skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC);
-	if (!skb) {
-		eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_put_rcv()\n", chan->No);
-		return;
-	}
-	skb_reserve(skb, MAX_HEADER_LEN);
-	memcpy(skb_put(skb, len), Data, len);
-	ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
-}
-
-static void
-idi_faxdata_rcv(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
-{
-	eicon_OBJBUFFER InBuf;
-	eicon_OBJBUFFER LineBuf;
-	unsigned int Length = 0;
-	unsigned int aLength = 0;
-	unsigned int ObjectSize = 0;
-	unsigned int ObjHeadLen = 0;
-	unsigned int ObjDataLen = 0;
-	__u8 Recordtype;
-	__u8 PageHeaderLen;	
-	__u8 Event;
-	eicon_sff_pagehead *ob_page;
-
-	__u16 Cl2Eol = 0x8000;
-
-#	define EVENT_NONE	0
-#	define EVENT_NEEDDATA	1
-
-	if (!chan->fax) {
-		eicon_log(ccard, 1, "idi_fax: rcvdata with NULL fax struct, ERROR\n");
-		return;
-	}
-
-
-	
-	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
-		InBuf.Data = skb->data;
-		InBuf.Size = skb->len;
-		InBuf.Len  = 0;
-		InBuf.Next = InBuf.Data;
-		LineBuf.Data = chan->fax2.abLine;
-		LineBuf.Size = sizeof(chan->fax2.abLine);
-		LineBuf.Len  = chan->fax2.LineLen;
-		LineBuf.Next = LineBuf.Data + LineBuf.Len;
-
-		Event = EVENT_NONE;
-		while (Event == EVENT_NONE) {
-			switch(chan->fax2.NextObject) {
-				case FAX_OBJECT_DOCU:
-						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
-						if (Length < sizeof(eicon_sff_dochead)) {
-							Event = EVENT_NEEDDATA;
-							break;
-						}
-						ObjectSize = sizeof(eicon_sff_dochead);
-						Length = ObjectSize;
-						if (LineBuf.Len < Length) {
-							Length -= LineBuf.Len;
-							LineBuf.Len = 0;
-							LineBuf.Next = LineBuf.Data;
-							InBuf.Len += Length;
-							InBuf.Next += Length;
-						} else {
-							LineBuf.Len -= Length;
-							LineBuf.Next = LineBuf.Data + LineBuf.Len;
-							memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
-						}
-						chan->fax2.PrevObject = FAX_OBJECT_DOCU;
-						chan->fax2.NextObject = FAX_OBJECT_PAGE;
-					break;
-
-				case FAX_OBJECT_PAGE:
-						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
-						if (Length < 2) {
-							Event = EVENT_NEEDDATA;
-							break;
-						}
-						if (LineBuf.Len == 0) {
-							*LineBuf.Next++ = *InBuf.Next++;
-							LineBuf.Len++;
-							InBuf.Len++;
-						}
-						if (LineBuf.Len == 1) {
-							*LineBuf.Next++ = *InBuf.Next++;
-							LineBuf.Len++;
-							InBuf.Len++;
-						}
-						PageHeaderLen = *(LineBuf.Data + 1);
-						ObjectSize = (PageHeaderLen == 0) ? 2 : sizeof(eicon_sff_pagehead);
-						if (Length < ObjectSize) {
-							Event = EVENT_NEEDDATA;
-							break;
-						}
-						Length = ObjectSize;
-						/* extract page dimensions */
-						if (LineBuf.Len < Length) {
-							aLength = Length - LineBuf.Len;
-							memcpy(LineBuf.Next, InBuf.Next, aLength);
-							LineBuf.Next += aLength;
-							InBuf.Next += aLength;
-							LineBuf.Len += aLength;
-							InBuf.Len += aLength;
-						}
-						if (Length > 2) {
-							ob_page = (eicon_sff_pagehead *)LineBuf.Data;
-							switch(ob_page->linelength) {
-								case 2048:
-									chan->fax->r_width = 1;
-									break;
-								case 2432:
-									chan->fax->r_width = 2;
-									break;
-								case 1216:
-									chan->fax->r_width = 3;
-									break;
-								case 864:
-									chan->fax->r_width = 4;
-									break;
-								case 1728:
-								default:
-									chan->fax->r_width = 0;
-							}
-							switch(ob_page->pagelength) {
-								case 1143:
-								case 2287:
-									chan->fax->r_length = 0;
-									break;
-								case 1401:
-								case 2802:
-									chan->fax->r_length = 1;
-									break;
-								default:
-									chan->fax->r_length = 2;
-							}
-							eicon_log(ccard, 128, "rSFF-Head: linelength = %d\n", ob_page->linelength);
-							eicon_log(ccard, 128, "rSFF-Head: pagelength = %d\n", ob_page->pagelength);
-						}
-						LineBuf.Len -= Length;
-						LineBuf.Next = LineBuf.Data + LineBuf.Len;
-						memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
-
-						chan->fax2.PrevObject = FAX_OBJECT_PAGE;
-						chan->fax2.NextObject = FAX_OBJECT_LINE;
-					break;
-
-				case FAX_OBJECT_LINE:
-						Length = LineBuf.Len + (InBuf.Size - InBuf.Len);
-						if (Length < 1) {
-							Event = EVENT_NEEDDATA;
-							break;
-						}
-						if (LineBuf.Len == 0) {
-							*LineBuf.Next++ = *InBuf.Next++;
-							LineBuf.Len++;
-							InBuf.Len++;
-						}
-						Recordtype = *LineBuf.Data;
-						if (Recordtype == 0) {
-							/* recordtype pixel row (2 byte length) */
-							ObjHeadLen = 3;
-							if (Length < ObjHeadLen) {
-								Event = EVENT_NEEDDATA;
-								break;
-							}
-							while (LineBuf.Len < ObjHeadLen) {
-								*LineBuf.Next++ = *InBuf.Next++;
-								LineBuf.Len++;
-								InBuf.Len++;
-							}
-							ObjDataLen = *((__u16*) (LineBuf.Data + 1));
-							ObjectSize = ObjHeadLen + ObjDataLen;
-							if (Length < ObjectSize) {
-								Event = EVENT_NEEDDATA;
-								break;
-							}
-						} else
-						if ((Recordtype >= 1) && (Recordtype <= 216)) {
-							/* recordtype pixel row (1 byte length) */
-							ObjHeadLen = 1;
-							ObjDataLen = Recordtype;
-							ObjectSize = ObjHeadLen + ObjDataLen;
-							if (Length < ObjectSize) {
-								Event = EVENT_NEEDDATA;
-								break;
-							}
-						} else
-						if ((Recordtype >= 217) && (Recordtype <= 253)) {
-							/* recordtype empty lines */
-							ObjHeadLen = 1;
-							ObjDataLen = 0;
-							ObjectSize = ObjHeadLen + ObjDataLen;
-							LineBuf.Len--;
-							LineBuf.Next = LineBuf.Data + LineBuf.Len;
-							memmove(LineBuf.Data, LineBuf.Data + 1, LineBuf.Len);
-							break;
-						} else
-						if (Recordtype == 254) {
-							/* recordtype page header */
-							chan->fax2.PrevObject = FAX_OBJECT_LINE;
-							chan->fax2.NextObject = FAX_OBJECT_PAGE;
-							break;
-						} else {
-							/* recordtype user information */
-							ObjHeadLen = 2;
-							if (Length < ObjHeadLen) {
-								Event = EVENT_NEEDDATA;
-								break;
-							}
-							while (LineBuf.Len < ObjHeadLen) {
-								*LineBuf.Next++ = *InBuf.Next++;
-								LineBuf.Len++;
-								InBuf.Len++;
-							}
-							ObjDataLen = *(LineBuf.Data + 1);
-							ObjectSize = ObjHeadLen + ObjDataLen;
-							if (ObjDataLen == 0) {
-								/* illegal line coding */
-								LineBuf.Len -= ObjHeadLen;
-								LineBuf.Next = LineBuf.Data + LineBuf.Len;
-								memmove(LineBuf.Data, LineBuf.Data + ObjHeadLen, LineBuf.Len);
-								break;
-							} else {
-								/* user information */
-								if (Length < ObjectSize) {
-									Event = EVENT_NEEDDATA;
-									break;
-								}
-								Length = ObjectSize;
-								if (LineBuf.Len < Length) {
-									Length -= LineBuf.Len;
-									LineBuf.Len = 0;
-									LineBuf.Next = LineBuf.Data;
-									InBuf.Len += Length;
-									InBuf.Next += Length;
-								} else {
-									LineBuf.Len -= Length;
-									LineBuf.Next = LineBuf.Data + LineBuf.Len;
-									memmove(LineBuf.Data, LineBuf.Data + Length, LineBuf.Len);
-								}
-							}
-							break;	
-						}
-						Length = ObjectSize;
-						if (LineBuf.Len > ObjHeadLen) {
-							fax_put_rcv(ccard, chan, LineBuf.Data + ObjHeadLen,
-									(LineBuf.Len - ObjHeadLen));
-						}
-						Length -= LineBuf.Len;
-						LineBuf.Len = 0;
-						LineBuf.Next = LineBuf.Data;
-						if (Length > 0) {
-							fax_put_rcv(ccard, chan, InBuf.Next, Length);
-							InBuf.Len += Length;
-							InBuf.Next += Length;
-						}
-						fax_put_rcv(ccard, chan, (__u8 *)&Cl2Eol, sizeof(Cl2Eol));
-					break;
-			} /* end of switch (chan->fax2.NextObject) */
-		} /* end of while (Event==EVENT_NONE) */
-		if (InBuf.Len < InBuf.Size) {
-			Length = InBuf.Size - InBuf.Len;
-			if ((LineBuf.Len + Length) > LineBuf.Size) {
-				eicon_log(ccard, 1, "idi_fax: Ch%d: %d bytes dropping, small buffer\n", chan->No,
-					Length);
-				} else {
-					memcpy(LineBuf.Next, InBuf.Next, Length);
-					LineBuf.Len += Length;
-				}
-		}
-		chan->fax2.LineLen = LineBuf.Len;
-	} else { /* CONN_OUT */
-		/* On CONN_OUT we do not need incoming data, drop it */
-		/* maybe later for polling */
-	}
-
-#	undef EVENT_NONE
-#	undef EVENT_NEEDDATA
-
-	return;
-}
-
-static int
-idi_fax_send_outbuf(eicon_card *ccard, eicon_chan *chan, eicon_OBJBUFFER *OutBuf)
-{
-	struct sk_buff *skb;
-
-	skb = alloc_skb(OutBuf->Len, GFP_ATOMIC);
-	if (!skb) {
-		eicon_log(ccard, 1, "idi_err: Ch%d: alloc_skb failed in fax_send_outbuf()\n", chan->No);
-		return(-1);
-	}
-	memcpy(skb_put(skb, OutBuf->Len), OutBuf->Data, OutBuf->Len);
-
-	OutBuf->Len = 0;
-	OutBuf->Next = OutBuf->Data;
-
-	return(idi_send_data(ccard, chan, 0, skb, 1, 0));
-}
-
-int
-idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb)
-{
-	isdn_ctrl cmd;
-	eicon_OBJBUFFER InBuf;
-	__u8 InData;
-	__u8 InMask;
-	eicon_OBJBUFFER OutBuf;
-	eicon_OBJBUFFER LineBuf;
-	__u32 LineData;
-	unsigned int LineDataLen;
-	__u8 Byte;
-	__u8 Event;
-	int ret = 1;
-
-#	define EVENT_NONE	0
-#	define EVENT_EOD	1
-#	define EVENT_EOL 	2
-#	define EVENT_EOP 	3
-
-	if ((!ccard) || (!chan))
-		return -1;
-
-	if (!chan->fax) {
-		eicon_log(ccard, 1, "idi_fax: senddata with NULL fax struct, ERROR\n");
-		return -1;
-	}
-
-	if (chan->fax->direction == ISDN_TTY_FAX_CONN_IN) {
-		/* Simply ignore any data written in data mode when receiving a fax.    */
-		/* This is not completely correct because only XON's should come here.  */
-        	dev_kfree_skb(skb);
-		return 1;
-	}
-
-	if (chan->fax->phase != ISDN_FAX_PHASE_C) {
-        	dev_kfree_skb(skb);
-		return 1;
-	}
-
-        if (chan->queued + skb->len > 1200)
-                return 0;
-	if (chan->pqueued > 1)
-		return 0;
-
-	InBuf.Data = skb->data;
-	InBuf.Size = skb->len;
-	InBuf.Len  = 0;
-	InBuf.Next = InBuf.Data;
-	InData = 0;
-	InMask = 0;
-
-	LineBuf.Data = chan->fax2.abLine;
-	LineBuf.Size = sizeof(chan->fax2.abLine);
-	LineBuf.Len  = chan->fax2.LineLen;
-	LineBuf.Next = LineBuf.Data + LineBuf.Len;
-	LineData = chan->fax2.LineData;
-	LineDataLen = chan->fax2.LineDataLen;
-
-	OutBuf.Data = chan->fax2.abFrame;
-	OutBuf.Size = sizeof(chan->fax2.abFrame);
-	OutBuf.Len = 0;
-	OutBuf.Next = OutBuf.Data;
-
-	Event = EVENT_NONE;
-
-	chan->fax2.Eop = 0;
-
-	for (;;) {
-	  for (;;) {
-		if (InMask == 0) {
-			if (InBuf.Len >= InBuf.Size) {
-				Event = EVENT_EOD;
-				break;
-			}
-			if ((chan->fax2.Dle != _DLE_) && *InBuf.Next == _DLE_) {
-				chan->fax2.Dle = _DLE_;
-				InBuf.Next++;
-				InBuf.Len++;
-				if (InBuf.Len >= InBuf.Size) {
-					Event = EVENT_EOD;
-					break;
-				}
-			}
-			if (chan->fax2.Dle == _DLE_) {
-				chan->fax2.Dle = 0;
-				if (*InBuf.Next == _ETX_) {
-					Event = EVENT_EOP;
-					break;
-				} else
-				if (*InBuf.Next == _DLE_) {
-					/* do nothing */
-				} else {
-					eicon_log(ccard, 1,
-						"idi_err: Ch%d: unknown DLE escape %02x found\n",
-							chan->No, *InBuf.Next);
-					InBuf.Next++;
-					InBuf.Len++;
-					if (InBuf.Len >= InBuf.Size) {
-						Event = EVENT_EOD;
-						break;
-					}
-				}
-			}
-			InBuf.Len++;
-			InData = *InBuf.Next++;
-			InMask = (chan->fax->bor) ? 0x80 : 0x01;
-		}
-		while (InMask) {
-			LineData >>= 1;
-			LineDataLen++;
-			if (InData & InMask)
-				LineData |= 0x80000000;
-			if (chan->fax->bor)
-				InMask >>= 1;
-			else
-				InMask <<= 1;
-
-			if ((LineDataLen >= T4_EOL_BITSIZE) &&
-			   ((LineData & T4_EOL_MASK_DWORD) == T4_EOL_DWORD)) {
-				Event = EVENT_EOL;
-				if (LineDataLen > T4_EOL_BITSIZE) {
-					Byte = (__u8)
-						((LineData & ~T4_EOL_MASK_DWORD) >>
-						(32 - LineDataLen));
-					if (Byte == 0) {
-						if (! chan->fax2.NullByteExist) {
-							chan->fax2.NullBytesPos = LineBuf.Len;
-							chan->fax2.NullByteExist = 1;
-						}
-					} else {
-						chan->fax2.NullByteExist = 0;
-					}
-					if (LineBuf.Len < LineBuf.Size) {
-						*LineBuf.Next++  = Byte;
-						LineBuf.Len++;
-					}
-				}
-				LineDataLen = 0;
-				break;
-			}
-			if (LineDataLen >= T4_EOL_BITSIZE + 8) {
-				Byte = (__u8)
-					((LineData & ~T4_EOL_MASK_DWORD) >>
-					(32 - T4_EOL_BITSIZE - 8));
-				LineData &= T4_EOL_MASK_DWORD;
-				LineDataLen = T4_EOL_BITSIZE;
-				if (Byte == 0) {
-					if (! chan->fax2.NullByteExist) {
-						chan->fax2.NullBytesPos = LineBuf.Len;
-						chan->fax2.NullByteExist = 1;
-					}
-				} else {
-					chan->fax2.NullByteExist = 0;
-				}
-				if (LineBuf.Len < LineBuf.Size) {
-					*LineBuf.Next++  = Byte; 
-					LineBuf.Len++;
-				}
-			}
-		}
-		if (Event != EVENT_NONE)
-			break;
-	  }
-
-		if ((Event != EVENT_EOL) && (Event != EVENT_EOP))
-			break;
-
-		if ((Event == EVENT_EOP) && (LineDataLen > 0)) {
-			LineData >>= 32 - LineDataLen;
-			LineDataLen = 0;
-			while (LineData != 0) {
-				Byte = (__u8) LineData;
-				LineData >>= 8;
-				if (Byte == 0) {
-					if (! chan->fax2.NullByteExist) {
-						chan->fax2.NullBytesPos = LineBuf.Len;
-						chan->fax2.NullByteExist = 1;
-					}
-				} else {
-					chan->fax2.NullByteExist = 0;
-				}
-				if (LineBuf.Len < LineBuf.Size) {
-					*LineBuf.Next++  = Byte;
-					LineBuf.Len++;
-				}
-				
-			}
-		}
-		if (chan->fax2.NullByteExist) {
-			if (chan->fax2.NullBytesPos == 0) {
-				LineBuf.Len = 0;
-			} else {
-				LineBuf.Len = chan->fax2.NullBytesPos + 1;
-			}
-		}
-		if (LineBuf.Len > 0) {
-			if (OutBuf.Len + LineBuf.Len + SFF_LEN_FLD_SIZE > OutBuf.Size) {
-				ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
-			}
-			if (LineBuf.Len <= 216) {
-				*OutBuf.Next++ = (__u8) LineBuf.Len;
-				OutBuf.Len++;
-			} else {
-				*OutBuf.Next++ = 0;
-				*((__u16 *) OutBuf.Next)++ = (__u16) LineBuf.Len;
-				OutBuf.Len += 3;
-			}
-			memcpy(OutBuf.Next, LineBuf.Data, LineBuf.Len);
-			OutBuf.Next += LineBuf.Len;
-			OutBuf.Len  += LineBuf.Len;
-		}
-		LineBuf.Len = 0;
-		LineBuf.Next = LineBuf.Data;
-		chan->fax2.NullByteExist = 0;
-		if (Event == EVENT_EOP)
-			break;
-
-		Event = EVENT_NONE;
-	}
-
-	if (Event == EVENT_EOP) {
-		chan->fax2.Eop = 1;
-		chan->fax2.PageCount++;
-		cmd.driver = ccard->myid;
-		cmd.command = ISDN_STAT_FAXIND;
-		cmd.arg = chan->No;
-		chan->fax->r_code = ISDN_TTY_FAX_EOP;
-		ccard->interface.statcallb(&cmd);
-	}
-	if (OutBuf.Len > 0) {
-		ret = idi_fax_send_outbuf(ccard, chan, &OutBuf);
-	}
-
-	chan->fax2.LineLen = LineBuf.Len;
-	chan->fax2.LineData = LineData;
-	chan->fax2.LineDataLen = LineDataLen;
-
-#	undef EVENT_NONE
-#	undef EVENT_EOD
-#	undef EVENT_EOL
-#	undef EVENT_EOP
-
-	if (ret >= 0)
-	        dev_kfree_skb(skb);
-	if (ret == 0)
-		ret = 1;
-	return(ret);
-}
-
-static void
-idi_fax_hangup(eicon_card *ccard, eicon_chan *chan)
-{
-	isdn_ctrl cmd;
-
-	if (!chan->fax) {
-		eicon_log(ccard, 1, "idi_fax: hangup with NULL fax struct, ERROR\n");
-		return;
-	}
-	if ((chan->fax->direction == ISDN_TTY_FAX_CONN_OUT) &&
-	    (chan->fax->code == 0)) {
-		cmd.driver = ccard->myid;
-		cmd.command = ISDN_STAT_FAXIND;
-		cmd.arg = chan->No;
-		chan->fax->r_code = ISDN_TTY_FAX_PTS;
-		ccard->interface.statcallb(&cmd);
-	}
-	if ((chan->fax->code > 1) && (chan->fax->code < 120))
-		chan->fax->code += 120;
-	eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code);
-	chan->fax->r_code = ISDN_TTY_FAX_HNG;
-	cmd.driver = ccard->myid;
-	cmd.command = ISDN_STAT_FAXIND;
-	cmd.arg = chan->No;
-	ccard->interface.statcallb(&cmd);
-}
-
-#endif	/******** FAX ********/
-
-static int
-idi_send_udata(eicon_card *card, eicon_chan *chan, int UReq, u_char *buffer, int len)
-{
-	struct sk_buff *skb;
-	struct sk_buff *skb2;
-	eicon_REQ *reqbuf;
-	eicon_chan_ptr *chan2;
-
-	if ((chan->fsm_state == EICON_STATE_NULL) || (chan->fsm_state == EICON_STATE_LISTEN)) {
-		eicon_log(card, 1, "idi_snd: Ch%d: send udata on state %d !\n", chan->No, chan->fsm_state);
-		return -ENODEV;
-	}
-	eicon_log(card, 8, "idi_snd: Ch%d: udata 0x%x: %d %d %d %d\n", chan->No,
-			UReq, buffer[0], buffer[1], buffer[2], buffer[3]);
-
-	skb = alloc_skb(sizeof(eicon_REQ) + len + 1, GFP_ATOMIC);
-	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
-
-	if ((!skb) || (!skb2)) {
-		eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_udata()\n", chan->No);
-		if (skb) 
-			dev_kfree_skb(skb);
-		if (skb2) 
-			dev_kfree_skb(skb2);
-		return -ENOMEM;
-	}
-
-	chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
-	chan2->ptr = chan;
-
-	reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ));
-
-	reqbuf->Req = N_UDATA;
-	reqbuf->ReqCh = chan->e.IndCh;
-	reqbuf->ReqId = 1;
-
-	reqbuf->XBuffer.length = len + 1;
-	reqbuf->XBuffer.P[0] = UReq;
-	memcpy(&reqbuf->XBuffer.P[1], buffer, len);
-	reqbuf->Reference = 1; /* Net Entity */
-
-	skb_queue_tail(&chan->e.X, skb);
-	skb_queue_tail(&card->sndq, skb2);
-	eicon_tx_request(card);
-	return (0);
-}
-
-void
-idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value)
-{
-	u_char buf[6];
-	struct enable_dtmf_s *dtmf_buf = (struct enable_dtmf_s *)buf;
-
-	if ((!ccard) || (!chan))
-		return;
-
-	memset(buf, 0, 6);
-	switch(cmd) {
-		case ISDN_AUDIO_SETDD:
-			if (value[0]) {
-				dtmf_buf->tone = (__u16) (value[1] * 5);
-				dtmf_buf->gap = (__u16) (value[1] * 5);
-				idi_send_udata(ccard, chan,
-					DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER,
-					buf, 4);
-			} else {
-				idi_send_udata(ccard, chan,
-					DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER,
-					buf, 0);
-			}
-			break;
-	}
-}
-
-static void
-idi_parse_udata(eicon_card *ccard, eicon_chan *chan, unsigned char *buffer, int len)
-{
-	isdn_ctrl cmd;
-	eicon_dsp_ind *p = (eicon_dsp_ind *) (&buffer[1]);
-        static char *connmsg[] =
-        {"", "V.21", "V.23", "V.22", "V.22bis", "V.32bis", "V.34",
-         "V.8", "Bell 212A", "Bell 103", "V.29 Leased", "V.33 Leased", "V.90",
-         "V.21 CH2", "V.27ter", "V.29", "V.33", "V.17", "V.32", "K56Flex",
-         "X2", "V.18", "V.18LH", "V.18HL", "V.21LH", "V.21HL",
-         "Bell 103LH", "Bell 103HL", "V.23", "V.23", "EDT 110",
-         "Baudot45", "Baudot47", "Baudot50", "DTMF" };
-	static u_char dtmf_code[] = {
-	'1','4','7','*','2','5','8','0','3','6','9','#','A','B','C','D'
-	};
-
-	if ((!ccard) || (!chan))
-		return;
-
-	switch (buffer[0]) {
-		case DSP_UDATA_INDICATION_SYNC:
-			eicon_log(ccard, 16, "idi_ind: Ch%d: UDATA_SYNC time %d\n", chan->No, p->time);
-			break;
-		case DSP_UDATA_INDICATION_DCD_OFF:
-			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_OFF time %d\n", chan->No, p->time);
-			break;
-		case DSP_UDATA_INDICATION_DCD_ON:
-			if ((chan->l2prot == ISDN_PROTO_L2_MODEM) &&
-			   ((chan->fsm_state == EICON_STATE_IBWAIT) ||
-			    (chan->fsm_state == EICON_STATE_WMCONN))) {
-				chan->fsm_state = EICON_STATE_ACTIVE;
-				cmd.driver = ccard->myid;
-				cmd.command = ISDN_STAT_BCONN;
-				cmd.arg = chan->No;
-                                if (p->norm > 34) {
-                                  sprintf(cmd.parm.num, "%d/(%d)", p->speed, p->norm);
-                                } else {
-                                  sprintf(cmd.parm.num, "%d/%s", p->speed, connmsg[p->norm]);
-                                }
-				ccard->interface.statcallb(&cmd);
-			}
-			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DCD_ON time %d\n", chan->No, p->time);
-			eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
-				p->norm, p->options, p->speed, p->delay); 
-			break;
-		case DSP_UDATA_INDICATION_CTS_OFF:
-			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_OFF time %d\n", chan->No, p->time);
-			break;
-		case DSP_UDATA_INDICATION_CTS_ON:
-			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_CTS_ON time %d\n", chan->No, p->time);
-			eicon_log(ccard, 8, "idi_ind: Ch%d: %d %d %d %d\n", chan->No,
-				p->norm, p->options, p->speed, p->delay); 
-			break;
-		case DSP_UDATA_INDICATION_DISCONNECT:
-			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DISCONNECT cause %d\n", chan->No, buffer[1]);
-			break;
-		case DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED:
-			eicon_log(ccard, 8, "idi_ind: Ch%d: UDATA_DTMF_REC '%c'\n", chan->No,
-				dtmf_code[buffer[1]]);
-			cmd.driver = ccard->myid;
-			cmd.command = ISDN_STAT_AUDIO;
-			cmd.parm.num[0] = ISDN_AUDIO_DTMF;
-			cmd.parm.num[1] = dtmf_code[buffer[1]];
-			cmd.arg = chan->No;
-			ccard->interface.statcallb(&cmd);
-			break;
-		default:
-			eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED UDATA Indication 0x%02x\n", chan->No, buffer[0]);
-	}
-}
-
-static void
-eicon_parse_trace(eicon_card *ccard, unsigned char *buffer, int len)
-{
-	int i,j,n;
-	int buflen = len * 3 + 30;
-	char *p;
-	struct trace_s {
-		unsigned long time;
-		unsigned short size;
-		unsigned short code;
-		unsigned char data[1];
-	} *q;
-
-	if (!(p = kmalloc(buflen, GFP_ATOMIC))) {
-		eicon_log(ccard, 1, "idi_err: Ch??: could not allocate trace buffer\n");
-		return;
-	}
-	memset(p, 0, buflen);
-	q = (struct trace_s *)buffer;
-
-	if (DebugVar & 512) {
-		if ((q->code == 3) || (q->code == 4)) {
-			n = (short) *(q->data);
-			if (n) {
-				j = sprintf(p, "DTRC:");
-				for (i = 0; i < n; i++) {
-					j += sprintf(p + j, "%02x ", q->data[i+2]);
-				}
-				j += sprintf(p + j, "\n");
-			}
-		}
-	} else {
-		j = sprintf(p, "XLOG: %lx %04x %04x ",
-			q->time, q->size, q->code);
-
-		for (i = 0; i < q->size; i++) {
-			j += sprintf(p + j, "%02x ", q->data[i]);
-		}
-		j += sprintf(p + j, "\n");
-	}
-	if (strlen(p))
-		eicon_putstatus(ccard, p);
-	kfree(p);
-}
-
-void
-idi_handle_ind(eicon_card *ccard, struct sk_buff *skb)
-{
-	int tmp;
-	char tnum[64];
-	int dlev;
-	int free_buff;
-  eicon_IND *ind = (eicon_IND *)skb->data;
-	eicon_chan *chan;
-	idi_ind_message message;
-	isdn_ctrl cmd;
-
-	if (!ccard) {
-		eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ind\n");
-  		dev_kfree_skb(skb);
-		return;
-	}
-
-	if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
-		eicon_log(ccard, 1, "idi_err: Ch??: null chan in handle_ind\n");
-  		dev_kfree_skb(skb);
-		return;
-	}
-	
-	if ((ind->Ind != 8) && (ind->Ind != 0xc))
-		dlev = 144;
-	else
-		dlev = 128;
-
-       	eicon_log(ccard, dlev, "idi_hdl: Ch%d: Ind=%x Id=%x Ch=%x MInd=%x MLen=%x Len=%x\n", chan->No,
-	        ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
-
-	free_buff = 1;
-	/* Signal Layer */
-	if (chan->e.D3Id == ind->IndId) {
-		idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
-		switch(ind->Ind) {
-			case HANGUP:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Hangup\n", chan->No);
-		    skb_queue_purge(&chan->e.X);
-				chan->queued = 0;
-				chan->pqueued = 0;
-				chan->waitq = 0;
-				chan->waitpq = 0;
-				if (message.e_cau[0] & 0x7f) {
-					cmd.driver = ccard->myid;
-					cmd.arg = chan->No;
-					sprintf(cmd.parm.num,"E%02x%02x", 
-						chan->cause[0]&0x7f, message.e_cau[0]&0x7f); 
-					cmd.command = ISDN_STAT_CAUSE;
-					ccard->interface.statcallb(&cmd);
-				}
-				chan->cause[0] = 0; 
-				if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
-				    ((chan->l2prot == ISDN_PROTO_L2_FAX) &&
-				    (chan->fsm_state == EICON_STATE_OBWAIT))) {
-					chan->fsm_state = EICON_STATE_NULL;
-				} else {
-					if (chan->e.B2Id)
-						idi_do_req(ccard, chan, REMOVE, 1);
-					chan->statectrl &= ~WAITING_FOR_HANGUP;
-					chan->statectrl &= ~IN_HOLD;
-					if (chan->statectrl & HAVE_CONN_REQ) {
-						eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No);
-						chan->statectrl &= ~HAVE_CONN_REQ;
-						if ((chan->tskb1) && (chan->tskb2)) {
-							skb_queue_tail(&chan->e.X, chan->tskb1);
-							skb_queue_tail(&ccard->sndq, chan->tskb2); 
-						}
-						chan->tskb1 = NULL;
-						chan->tskb2 = NULL;
-					} else {
-						chan->fsm_state = EICON_STATE_NULL;
-						cmd.driver = ccard->myid;
-						cmd.arg = chan->No;
-						cmd.command = ISDN_STAT_DHUP;
-						ccard->interface.statcallb(&cmd);
-						eicon_idi_listen_req(ccard, chan);
-#ifdef CONFIG_ISDN_TTY_FAX
-						chan->fax = 0;
-#endif
-					}
-				}
-				break;
-			case INDICATE_IND:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Indicate_Ind\n", chan->No);
-				if (chan->fsm_state != EICON_STATE_LISTEN) {
-					eicon_log(ccard, 1, "idi_err: Ch%d: Incoming call on wrong state (%d).\n",
-						chan->No, chan->fsm_state);
-					idi_do_req(ccard, chan, HANGUP, 0);
-					break;
-				}
-				chan->fsm_state = EICON_STATE_ICALL;
-				idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2);
-				strcpy(chan->cpn, message.cpn + 1);
-				strcpy(chan->oad, message.oad);
-				strcpy(chan->dsa, message.dsa);
-				strcpy(chan->osa, message.osa);
-				chan->plan = message.plan;
-				chan->screen = message.screen;
-				try_stat_icall_again: 
-				cmd.driver = ccard->myid;
-				cmd.command = ISDN_STAT_ICALL;
-				cmd.arg = chan->No;
-				cmd.parm.setup.si1 = chan->si1;
-				cmd.parm.setup.si2 = chan->si2;
-				strcpy(tnum, chan->cpn);
-				if (strlen(chan->dsa)) {
-					strcat(tnum, ".");
-					strcat(tnum, chan->dsa);
-				}
-				tnum[ISDN_MSNLEN - 1] = 0;
-				strcpy(cmd.parm.setup.eazmsn, tnum);
-				strcpy(tnum, chan->oad);
-				if (strlen(chan->osa)) {
-					strcat(tnum, ".");
-					strcat(tnum, chan->osa);
-				}
-				tnum[ISDN_MSNLEN - 1] = 0;
-				strcpy(cmd.parm.setup.phone, tnum);
-				cmd.parm.setup.plan = chan->plan;
-				cmd.parm.setup.screen = chan->screen;
-				tmp = ccard->interface.statcallb(&cmd);
-				switch(tmp) {
-					case 0: /* no user responding */
-						idi_do_req(ccard, chan, HANGUP, 0);
-						chan->fsm_state = EICON_STATE_NULL;
-						break;
-					case 1: /* alert */
-						eicon_log(ccard, 8, "idi_req: Ch%d: Call Alert\n", chan->No);
-						if ((chan->fsm_state == EICON_STATE_ICALL) || (chan->fsm_state == EICON_STATE_ICALLW)) {
-							chan->fsm_state = EICON_STATE_ICALL;
-							idi_do_req(ccard, chan, CALL_ALERT, 0);
-						}
-						break;
-					case 2: /* reject */
-						eicon_log(ccard, 8, "idi_req: Ch%d: Call Reject\n", chan->No);
-						idi_do_req(ccard, chan, REJECT, 0);
-						break;
-					case 3: /* incomplete number */
-						eicon_log(ccard, 8, "idi_req: Ch%d: Incomplete Number\n", chan->No);
-						chan->fsm_state = EICON_STATE_ICALLW;
-						break;
-				}
-				break;
-			case INFO_IND:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Info_Ind\n", chan->No);
-				if ((chan->fsm_state == EICON_STATE_ICALLW) &&
-				    (message.cpn[0])) {
-					strcat(chan->cpn, message.cpn + 1);
-					goto try_stat_icall_again;
-				}
-				break;
-			case CALL_IND:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Ind\n", chan->No);
-				if ((chan->fsm_state == EICON_STATE_ICALL) ||
-                                     (chan->fsm_state == EICON_STATE_WMCONN) ||
-                                     (chan->fsm_state == EICON_STATE_IWAIT)) {
-					chan->fsm_state = EICON_STATE_IBWAIT;
-					cmd.driver = ccard->myid;
-					cmd.command = ISDN_STAT_DCONN;
-					cmd.arg = chan->No;
-					ccard->interface.statcallb(&cmd);
-					switch(chan->l2prot) {
-						case ISDN_PROTO_L2_FAX:
-#ifdef CONFIG_ISDN_TTY_FAX
-							if (chan->fax)
-								chan->fax->phase = ISDN_FAX_PHASE_A;
-#endif
-							break;
-						case ISDN_PROTO_L2_MODEM:
-							/* do nothing, wait for connect */
-							break;
-						case ISDN_PROTO_L2_V11096:
-						case ISDN_PROTO_L2_V11019:
-						case ISDN_PROTO_L2_V11038:
-						case ISDN_PROTO_L2_TRANS:
-							idi_do_req(ccard, chan, N_CONNECT, 1);
-							break;
-						default:
-							/* On most incoming calls we use automatic connect */
-							/* idi_do_req(ccard, chan, N_CONNECT, 1); */
-							break;
-					}
-				} else {
-					if (chan->fsm_state != EICON_STATE_ACTIVE)
-						idi_hangup(ccard, chan);
-				}
-				break;
-			case CALL_CON:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
-				if (chan->fsm_state == EICON_STATE_OCALL) {
-					/* check if old NetID has been removed */
-					if (chan->e.B2Id) {
-						eicon_log(ccard, 1, "idi_ind: Ch%d: old net_id %x still exist, removing.\n",
-							chan->No, chan->e.B2Id);
-						idi_do_req(ccard, chan, REMOVE, 1);
-					}
-#ifdef CONFIG_ISDN_TTY_FAX
-					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-						if (chan->fax) {
-							chan->fax->phase = ISDN_FAX_PHASE_A;
-						} else {
-							eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n");
-							idi_hangup(ccard, chan);
-							break;
-						}
-					}
-#endif
-					chan->fsm_state = EICON_STATE_OBWAIT;
-					cmd.driver = ccard->myid;
-					cmd.command = ISDN_STAT_DCONN;
-					cmd.arg = chan->No;
-					ccard->interface.statcallb(&cmd);
-
-					idi_do_req(ccard, chan, ASSIGN, 1); 
-					idi_do_req(ccard, chan, N_CONNECT, 1);
-				} else
-					idi_hangup(ccard, chan);
-				break;
-			case AOC_IND:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No);
-				break;
-			case CALL_HOLD_ACK:
-				chan->statectrl |= IN_HOLD;
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No);
-				break;
-			case SUSPEND_REJ:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No);
-				break;
-			case SUSPEND:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No);
-				break;
-			case RESUME:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No);
-				break;
-			default:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
-		}
-	}
-	/* Network Layer */
-	else if (chan->e.B2Id == ind->IndId) {
-
-		if (chan->No == ccard->nchannels) {
-			/* Management Indication */
-			if (ind->Ind == 0x04) { /* Trace_Ind */
-				eicon_parse_trace(ccard, ind->RBuffer.P, ind->RBuffer.length);
-			} else {
-				idi_IndParse(ccard, chan, &message, ind->RBuffer.P, ind->RBuffer.length);
-				chan->fsm_state = 1;
-			}
-		} 
-		else
-		switch(ind->Ind) {
-			case N_CONNECT_ACK:
-				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
-				if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
-					chan->fsm_state = EICON_STATE_WMCONN;
-					break;
-				}
-				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-#ifdef CONFIG_ISDN_TTY_FAX
-					chan->fsm_state = EICON_STATE_ACTIVE;
-					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
-					if (chan->fax) {
-						if (chan->fax->phase == ISDN_FAX_PHASE_B) {
-							idi_fax_send_header(ccard, chan, 2);
-							cmd.driver = ccard->myid;
-							cmd.command = ISDN_STAT_FAXIND;
-							cmd.arg = chan->No;
-							chan->fax->r_code = ISDN_TTY_FAX_DCS;
-							ccard->interface.statcallb(&cmd);
-						}
-					}
-					else {
-						eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n");
-					}
-#endif
-					break;
-				}
-				chan->fsm_state = EICON_STATE_ACTIVE;
-				cmd.driver = ccard->myid;
-				cmd.command = ISDN_STAT_BCONN;
-				cmd.arg = chan->No;
-				strcpy(cmd.parm.num, "64000");
-				ccard->interface.statcallb(&cmd);
-				break; 
-			case N_CONNECT:
-				eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
-				chan->e.IndCh = ind->IndCh;
-				if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1);
-				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-					break;
-				}
-				if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
-					chan->fsm_state = EICON_STATE_WMCONN;
-					break;
-				}
-				chan->fsm_state = EICON_STATE_ACTIVE;
-				cmd.driver = ccard->myid;
-				cmd.command = ISDN_STAT_BCONN;
-				cmd.arg = chan->No;
-				strcpy(cmd.parm.num, "64000");
-				ccard->interface.statcallb(&cmd);
-				break; 
-			case N_DISC:
-				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No);
-				if (chan->e.B2Id) {
-		      skb_queue_purge(&chan->e.X);
-					idi_do_req(ccard, chan, N_DISC_ACK, 1);
-					idi_do_req(ccard, chan, REMOVE, 1);
-				}
-#ifdef CONFIG_ISDN_TTY_FAX
-				if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){
-					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
-					idi_fax_hangup(ccard, chan);
-				}
-#endif
-				chan->e.IndCh = 0;
-				chan->queued = 0;
-				chan->pqueued = 0;
-				chan->waitq = 0;
-				chan->waitpq = 0;
-				if (!(chan->statectrl & IN_HOLD)) {
-					idi_do_req(ccard, chan, HANGUP, 0);
-				}
-				if (chan->fsm_state == EICON_STATE_ACTIVE) {
-					cmd.driver = ccard->myid;
-					cmd.command = ISDN_STAT_BHUP;
-					cmd.arg = chan->No;
-					ccard->interface.statcallb(&cmd);
-					chan->fsm_state = EICON_STATE_NULL;
-					if (!(chan->statectrl & IN_HOLD)) {
-						chan->statectrl |= WAITING_FOR_HANGUP;
-					}
-				}
-#ifdef CONFIG_ISDN_TTY_FAX
-				chan->fax = 0;
-#endif
-				break; 
-			case N_DISC_ACK:
-				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No);
-#ifdef CONFIG_ISDN_TTY_FAX
-				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
-					idi_fax_hangup(ccard, chan);
-				}
-#endif
-				break; 
-			case N_DATA_ACK:
-				eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No);
-				break;
-			case N_DATA:
-				skb_pull(skb, sizeof(eicon_IND) - 1);
-				eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
-				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-#ifdef CONFIG_ISDN_TTY_FAX
-					idi_faxdata_rcv(ccard, chan, skb);
-#endif
-				} else {
-					ccard->interface.rcvcallb_skb(ccard->myid, chan->No, skb);
-					free_buff = 0; 
-				}
-				break; 
-			case N_UDATA:
-				idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
-				break; 
-#ifdef CONFIG_ISDN_TTY_FAX
-			case N_EDATA:
-				idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
-				break; 
-#endif
-			default:
-				eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED NetIndication 0x%02x\n", chan->No, ind->Ind);
-		}
-	}
-	else {
-		eicon_log(ccard, 1, "idi_ind: Ch%d: Ind is neither SIG nor NET !\n", chan->No);
-	}
-   if (free_buff)
-	dev_kfree_skb(skb);
-}
-
-static int
-idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack)
-{
-  isdn_ctrl cmd;
-  int tqueued = 0;
-  int twaitpq = 0;
-
-	if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
-		/* I don't know why this happens, should not ! */
-		/* just ignoring this RC */
-		eicon_log(ccard, 16, "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, 
-			ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id);
-		return 1;
-	}
-
-	/* Management Interface */	
-	if (chan->No == ccard->nchannels) {
-		/* Managementinterface: changing state */
-		if (chan->e.Req != 0x02)
-			chan->fsm_state = 1;
-	}
-
-	/* Remove an Id */
-	if (chan->e.Req == REMOVE) {
-		if (ack->Reference != chan->e.ref) {
-			/* This should not happen anymore */
-			eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
-				ack->Reference, chan->e.ref);
-		}
-		ccard->IdTable[ack->RcId] = NULL;
-		if (!chan->e.ReqCh) 
-			chan->e.D3Id = 0;
-		else
-			chan->e.B2Id = 0;
-		eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
-			ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
-		return 1;
-	}
-
-	/* Signal layer */
-	if (!chan->e.ReqCh) {
-		eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
-			ack->RcId, ack->RcCh, ack->Reference);
-	} else {
-	/* Network layer */
-		switch(chan->e.Req & 0x0f) {
-			case N_CONNECT:
-				chan->e.IndCh = ack->RcCh;
-				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
-					ack->RcId, ack->RcCh, ack->Reference);
-				break;
-			case N_MDATA:
-			case N_DATA:
-				tqueued = chan->queued;
-				twaitpq = chan->waitpq;
-				if ((chan->e.Req & 0x0f) == N_DATA) {
-					chan->waitpq = 0;
-					if(chan->pqueued)
-						chan->pqueued--;
-#ifdef CONFIG_ISDN_TTY_FAX
-					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-						if (((chan->queued - chan->waitq) < 1) &&
-						    (chan->fax2.Eop)) {
-							chan->fax2.Eop = 0;
-							if (chan->fax) {
-								cmd.driver = ccard->myid;
-								cmd.command = ISDN_STAT_FAXIND;
-								cmd.arg = chan->No;
-								chan->fax->r_code = ISDN_TTY_FAX_SENT;
-								ccard->interface.statcallb(&cmd);
-							}
-							else {
-								eicon_log(ccard, 1, "idi_ack: Sent with NULL fax struct, ERROR\n");
-							}
-						}
-					}
-#endif
-				}
-				chan->queued -= chan->waitq;
-				if (chan->queued < 0) chan->queued = 0;
-				if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) {
-					cmd.driver = ccard->myid;
-					cmd.command = ISDN_STAT_BSENT;
-					cmd.arg = chan->No;
-					cmd.parm.length = twaitpq;
-					ccard->interface.statcallb(&cmd);
-				}
-				break;
-			default:
-				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
-					ack->RcId, ack->RcCh, ack->Reference);
-		}
-	}
-	return 1;
-}
-
-void
-idi_handle_ack(eicon_card *ccard, struct sk_buff *skb)
-{
-	int j;
-        eicon_RC *ack = (eicon_RC *)skb->data;
-	eicon_chan *chan;
-	isdn_ctrl cmd;
-	int dCh = -1;
-
-	if (!ccard) {
-		eicon_log(ccard, 1, "idi_err: Ch??: null card in handle_ack\n");
-		dev_kfree_skb(skb);
-		return;
-	}
-
-	if ((chan = ccard->IdTable[ack->RcId]) != NULL)
-		dCh = chan->No;
-
-	switch (ack->Rc) {
-		case OK_FC:
-		case N_FLOW_CONTROL:
-		case ASSIGN_RC:
-			eicon_log(ccard, 1, "idi_ack: Ch%d: unhandled RC 0x%x\n",
-				dCh, ack->Rc);
-			break;
-		case READY_INT:
-		case TIMER_INT:
-			/* we do nothing here */
-			break;
-
-		case OK:
-			if (!chan) {
-				eicon_log(ccard, 1, "idi_ack: Ch%d: OK on chan without Id\n", dCh);
-				break;
-			}
-			if (!idi_handle_ack_ok(ccard, chan, ack))
-				chan = NULL;
-			break;
-
-		case ASSIGN_OK:
-			if (chan) {
-				eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
-					chan->No, chan->e.D3Id, chan->e.B2Id);
-			}
-			for(j = 0; j < ccard->nchannels + 1; j++) {
-				if ((ccard->bch[j].e.ref == ack->Reference) &&
-					(ccard->bch[j].e.Req == ASSIGN)) {
-					if (!ccard->bch[j].e.ReqCh) 
-						ccard->bch[j].e.D3Id  = ack->RcId;
-					else
-						ccard->bch[j].e.B2Id  = ack->RcId;
-					ccard->IdTable[ack->RcId] = &ccard->bch[j];
-					chan = &ccard->bch[j];
-					break;
-				}
-			}
-			eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
-				ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
-			if (j > ccard->nchannels) {
-				eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", 
-					ack->Reference, ack->RcId);
-			}
-			break;
-
-		case OUT_OF_RESOURCES:
-		case UNKNOWN_COMMAND:
-		case WRONG_COMMAND:
-		case WRONG_ID:
-		case 0x08:  /* ADAPTER_DEAD */ 
-		case WRONG_CH:
-		case UNKNOWN_IE:
-		case WRONG_IE:
-		default:
-			if (!chan) {
-				eicon_log(ccard, 1, "idi_ack: Ch%d: Not OK !! on chan without Id\n", dCh);
-				break;
-			} else
-			switch (chan->e.Req) {
-				case 12:	/* Alert */
-					eicon_log(ccard, 2, "idi_err: Ch%d: Alert Not OK : Rc=%d Id=%x Ch=%d\n",
-						dCh, ack->Rc, ack->RcId, ack->RcCh);
-					break;
-				default:
-					if (dCh != ccard->nchannels)
-						eicon_log(ccard, 1, "idi_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
-							dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
-			}
-			if (dCh == ccard->nchannels) { /* Management */
-				chan->fsm_state = 2;
-				eicon_log(ccard, 8, "idi_err: Ch%d: Ack Not OK !!: Rc=%d Id=%x Ch=%d Req=%d\n",
-					dCh, ack->Rc, ack->RcId, ack->RcCh, chan->e.Req);
-			} else if (dCh >= 0) {
-					/* any other channel */
-					/* card reports error: we hangup */
-				idi_hangup(ccard, chan);
-				cmd.driver = ccard->myid;
-				cmd.command = ISDN_STAT_DHUP;
-				cmd.arg = chan->No;
-				ccard->interface.statcallb(&cmd);
-			}
-	}
-	if (chan) {
-		chan->e.ref = 0;
-		chan->e.busy = 0;
-	}
-	dev_kfree_skb(skb);
-}
-
-int
-idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk)
-{
-        struct sk_buff *xmit_skb;
-        struct sk_buff *skb2;
-        eicon_REQ *reqbuf;
-        eicon_chan_ptr *chan2;
-        int len, plen = 0, offset = 0;
-
-	if ((!card) || (!chan)) {
-		eicon_log(card, 1, "idi_err: Ch??: null card/chan in send_data\n");
-		return -1;
-	}
-
-        if (chan->fsm_state != EICON_STATE_ACTIVE) {
-		eicon_log(card, 1, "idi_snd: Ch%d: send bytes on state %d !\n", chan->No, chan->fsm_state);
-                return -ENODEV;
-	}
-
-        len = skb->len;
-	if (len > EICON_MAX_QUEUE)	/* too much for the shared memory */
-		return -1;
-        if (!len)
-                return 0;
-
-	if ((chk) && (chan->pqueued > 1))
-		return 0;
-
-	eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n",
-		chan->No, len, chan->pqueued);
-	while(offset < len) {
-
-		plen = ((len - offset) > 270) ? 270 : len - offset;
-
-	        xmit_skb = alloc_skb(plen + sizeof(eicon_REQ), GFP_ATOMIC);
-        	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
-
-	        if ((!xmit_skb) || (!skb2)) {
-        	        eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
-			if (xmit_skb) 
-				dev_kfree_skb(skb);
-			if (skb2) 
-				dev_kfree_skb(skb2);
-                	return -ENOMEM;
-	        }
-
-	        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
-        	chan2->ptr = chan;
-
-	        reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ));
-		if ((len - offset) > 270) {
-		        reqbuf->Req = N_MDATA;
-		} else {
-		        reqbuf->Req = N_DATA;
-			/* if (ack) reqbuf->Req |= N_D_BIT; */
-		}	
-        	reqbuf->ReqCh = chan->e.IndCh;
-	        reqbuf->ReqId = 1;
-		memcpy(&reqbuf->XBuffer.P, skb->data + offset, plen);
-		reqbuf->XBuffer.length = plen;
-		reqbuf->Reference = 1; /* Net Entity */
-
-		skb_queue_tail(&chan->e.X, xmit_skb);
-		skb_queue_tail(&card->sndq, skb2); 
-
-		offset += plen;
-	}
-	if (que) {
-		chan->queued += len;
-		chan->pqueued++;
-	}
-	eicon_tx_request(card);
-        dev_kfree_skb(skb);
-        return len;
-}
-
-
-static int
-eicon_idi_manage_assign(eicon_card *card)
-{
-        struct sk_buff *skb;
-        struct sk_buff *skb2;
-        eicon_REQ  *reqbuf;
-        eicon_chan     *chan;
-        eicon_chan_ptr *chan2;
-
-        chan = &(card->bch[card->nchannels]);
-
-        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
-        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
-
-        if ((!skb) || (!skb2)) {
-		eicon_log(card, 1, "idi_err: alloc_skb failed in manage_assign()\n");
-		if (skb) 
-			dev_kfree_skb(skb);
-		if (skb2) 
-			dev_kfree_skb(skb2);
-                return -ENOMEM;
-        }
-
-        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
-        chan2->ptr = chan;
-
-        reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
-
-        reqbuf->XBuffer.P[0] = 0;
-        reqbuf->Req = ASSIGN;
-        reqbuf->ReqCh = 0;
-        reqbuf->ReqId = MAN_ID;
-        reqbuf->XBuffer.length = 1;
-        reqbuf->Reference = 2; /* Man Entity */
-
-        skb_queue_tail(&chan->e.X, skb);
-        skb_queue_tail(&card->sndq, skb2);
-        eicon_tx_request(card);
-        return(0);
-}
-
-int
-eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb)
-{
-	int l = 0;
-	int ret = 0;
-	int timeout;
-	int i;
-        struct sk_buff *skb;
-        struct sk_buff *skb2;
-        eicon_REQ  *reqbuf;
-        eicon_chan     *chan;
-        eicon_chan_ptr *chan2;
-
-        chan = &(card->bch[card->nchannels]);
-
-	if (!(chan->e.D3Id)) {
-		chan->e.D3Id = 1;
-		skb_queue_purge(&chan->e.X);
-		chan->e.busy = 0;
- 
-		if ((ret = eicon_idi_manage_assign(card))) {
-			chan->e.D3Id = 0;
-			return(ret); 
-		}
-
-	        timeout = jiffies + 50;
-        	while (time_before(jiffies, timeout)) {
-	                if (chan->e.B2Id) break;
-        	        SLEEP(10);
-	        }
-	        if (!chan->e.B2Id) {
-			chan->e.D3Id = 0;
-			return -EIO;
-		}
-	}
-
-	chan->fsm_state = 0;
-
-	if (!(manbuf = kmalloc(sizeof(eicon_manifbuf), GFP_KERNEL))) {
-               	eicon_log(card, 1, "idi_err: alloc_manifbuf failed\n");
-		return -ENOMEM;
-	}
-	if (copy_from_user(manbuf, mb, sizeof(eicon_manifbuf))) {
-		kfree(manbuf);
-		return -EFAULT;
-	}
-
-        skb = alloc_skb(270 + sizeof(eicon_REQ), GFP_ATOMIC);
-        skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
-
-        if ((!skb) || (!skb2)) {
-               	eicon_log(card, 1, "idi_err_manif: alloc_skb failed in manage()\n");
-		if (skb) 
-			dev_kfree_skb(skb);
-		if (skb2) 
-			dev_kfree_skb(skb2);
-		kfree(manbuf);
-                return -ENOMEM;
-        }
-
-        chan2 = (eicon_chan_ptr *)skb_put(skb2, sizeof(eicon_chan_ptr));
-        chan2->ptr = chan;
-
-        reqbuf = (eicon_REQ *)skb_put(skb, 270 + sizeof(eicon_REQ));
-
-        reqbuf->XBuffer.P[l++] = ESC;
-        reqbuf->XBuffer.P[l++] = 6;
-        reqbuf->XBuffer.P[l++] = 0x80;
-	for (i = 0; i < manbuf->length[0]; i++)
-	        reqbuf->XBuffer.P[l++] = manbuf->data[i];
-        reqbuf->XBuffer.P[1] = manbuf->length[0] + 1;
-
-        reqbuf->XBuffer.P[l++] = 0;
-        reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ;
-        reqbuf->ReqCh = 0;
-        reqbuf->ReqId = 1;
-        reqbuf->XBuffer.length = l;
-        reqbuf->Reference = 2; /* Man Entity */
-
-        skb_queue_tail(&chan->e.X, skb);
-        skb_queue_tail(&card->sndq, skb2);
-
-	manbuf->count = 0;
-	manbuf->pos = 0;
-
-        eicon_tx_request(card);
-
-        timeout = jiffies + 50;
-        while (time_before(jiffies, timeout)) {
-                if (chan->fsm_state) break;
-                SLEEP(10);
-        }
-        if ((!chan->fsm_state) || (chan->fsm_state == 2)) {
-		kfree(manbuf);
-		return -EIO;
-	}
-	if (copy_to_user(mb, manbuf, sizeof(eicon_manifbuf))) {
-		kfree(manbuf);
-		return -EFAULT;
-	}
-
-	kfree(manbuf);
-  return(0);
-}
diff -Nru a/drivers/isdn/hardware/eicon/i4l_idi.h b/drivers/isdn/hardware/eicon/i4l_idi.h
--- a/drivers/isdn/hardware/eicon/i4l_idi.h	Sat Apr  3 19:38:41 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,381 +0,0 @@
-/* $Id: i4l_idi.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
- *
- * ISDN interface module for Eicon active cards.
- * I4L - IDI Interface
- *
- * Copyright 1998-2000  by Armin Schindler (mac@melware.de)
- * Copyright 1999-2002  Cytronics & Melware (info@melware.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef E_IDI_H
-#define E_IDI_H
-
-#include <linux/config.h>
-
-#undef N_DATA
-#undef ID_MASK
-
-#include "pc.h"
-
-#define AOC_IND  26		/* Advice of Charge                         */
-#define PI  0x1e                /* Progress Indicator               */
-#define NI  0x27                /* Notification Indicator           */
-
-/* defines for statectrl */
-#define WAITING_FOR_HANGUP	0x01
-#define HAVE_CONN_REQ		0x02
-#define IN_HOLD			0x04
-
-typedef struct {
-	char cpn[32];
-	char oad[32];
-	char dsa[32];
-	char osa[32];
-	__u8 plan;
-	__u8 screen;
-	__u8 sin[4];
-	__u8 chi[4];
-	__u8 e_chi[4];
-	__u8 bc[12];
-	__u8 e_bc[12];
- 	__u8 llc[18];
-	__u8 hlc[5];
-	__u8 cau[4];
-	__u8 e_cau[2];
-	__u8 e_mt;
-	__u8 dt[6];
-	char display[83];
-	char keypad[35];
-	char rdn[32];
-} idi_ind_message;
-
-typedef struct { 
-  __u16 next            __attribute__ ((packed));
-  __u8  Req             __attribute__ ((packed));
-  __u8  ReqId           __attribute__ ((packed));
-  __u8  ReqCh           __attribute__ ((packed));
-  __u8  Reserved1       __attribute__ ((packed));
-  __u16 Reference       __attribute__ ((packed));
-  __u8  Reserved[8]     __attribute__ ((packed));
-  eicon_PBUFFER XBuffer; 
-} eicon_REQ;
-
-typedef struct {
-  __u16 next            __attribute__ ((packed));
-  __u8  Rc              __attribute__ ((packed));
-  __u8  RcId            __attribute__ ((packed));
-  __u8  RcCh            __attribute__ ((packed));
-  __u8  Reserved1       __attribute__ ((packed));
-  __u16 Reference       __attribute__ ((packed));
-  __u8  Reserved2[8]    __attribute__ ((packed));
-} eicon_RC;
-
-typedef struct {
-  __u16 next            __attribute__ ((packed));
-  __u8  Ind             __attribute__ ((packed));
-  __u8  IndId           __attribute__ ((packed));
-  __u8  IndCh           __attribute__ ((packed));
-  __u8  MInd            __attribute__ ((packed));
-  __u16 MLength         __attribute__ ((packed));
-  __u16 Reference       __attribute__ ((packed));
-  __u8  RNR             __attribute__ ((packed));
-  __u8  Reserved        __attribute__ ((packed));
-  __u32 Ack             __attribute__ ((packed));
-  eicon_PBUFFER RBuffer;
-} eicon_IND;
-
-typedef struct {
-	__u8		*Data;
-	unsigned int	Size;
-	unsigned int	Len;
-	__u8		*Next;
-} eicon_OBJBUFFER;
-
-extern int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer);
-extern int idi_hangup(eicon_card *card, eicon_chan *chan);
-extern int idi_connect_res(eicon_card *card, eicon_chan *chan);
-extern int eicon_idi_listen_req(eicon_card *card, eicon_chan *chan);
-extern int idi_connect_req(eicon_card *card, eicon_chan *chan, char *phone,
-	                    char *eazmsn, int si1, int si2);
-
-extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
-extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
-extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
-extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk);
-extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value);
-extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm);
-#ifdef CONFIG_ISDN_TTY_FAX
-extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan);
-extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb);
-#endif
-
-#include "dsp_defs.h"
-
-#define DSP_UDATA_REQUEST_SWITCH_FRAMER         1
-/*
-parameters:
-  <byte> transmit framer type
-  <byte> receive framer type
-*/
-
-#define DSP_REQUEST_SWITCH_FRAMER_HDLC          0
-#define DSP_REQUEST_SWITCH_FRAMER_TRANSPARENT   1
-#define DSP_REQUEST_SWITCH_FRAMER_ASYNC         2
-
-
-#define DSP_UDATA_REQUEST_CLEARDOWN             2
-/*
-parameters:
-  - none -
-*/
-
-
-#define DSP_UDATA_REQUEST_TX_CONFIRMATION_ON    3
-/*
-parameters:
-  - none -
-*/
-
-
-#define DSP_UDATA_REQUEST_TX_CONFIRMATION_OFF   4
-/*
-parameters:
-  - none -
-*/
-
-typedef struct eicon_dsp_ind {
-	__u16	time		__attribute__ ((packed));
-	__u8	norm		__attribute__ ((packed));
-	__u16	options		__attribute__ ((packed));
-	__u32	speed		__attribute__ ((packed));
-	__u16	delay		__attribute__ ((packed));
-	__u32	txspeed		__attribute__ ((packed));
-	__u32	rxspeed		__attribute__ ((packed));
-} eicon_dsp_ind;
-
-#define DSP_CONNECTED_OPTION_V42_TRANS           0x0002
-#define DSP_CONNECTED_OPTION_V42_LAPM            0x0004
-#define DSP_CONNECTED_OPTION_SHORT_TRAIN         0x0008
-#define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
-
-#define DSP_UDATA_INDICATION_DISCONNECT         5
-/*
-returns:
-  <byte> cause
-*/
-
-#define DSP_DISCONNECT_CAUSE_NONE               0x00
-#define DSP_DISCONNECT_CAUSE_BUSY_TONE          0x01
-#define DSP_DISCONNECT_CAUSE_CONGESTION_TONE    0x02
-#define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY    0x03
-#define DSP_DISCONNECT_CAUSE_CLEARDOWN          0x04
-#define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT   0x05
-
-#define DSP_UDATA_INDICATION_TX_CONFIRMATION    6
-/*
-returns:
-  <word> confirmation number
-*/
-
-
-#define DSP_UDATA_REQUEST_SEND_DTMF_DIGITS      16
-/*
-parameters:
-  <word> tone duration (ms)
-  <word> gap duration (ms)
-  <byte> digit 0 tone code
-  ...
-  <byte> digit n tone code
-*/
-
-#define DSP_SEND_DTMF_DIGITS_HEADER_LENGTH      5
-
-#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_697_HZ    0x00
-#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_770_HZ    0x01
-#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_852_HZ    0x02
-#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_941_HZ    0x03
-#define DSP_DTMF_DIGIT_TONE_LOW_GROUP_MASK      0x03
-#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1209_HZ  0x00
-#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1336_HZ  0x04
-#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1477_HZ  0x08
-#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_1633_HZ  0x0c
-#define DSP_DTMF_DIGIT_TONE_HIGH_GROUP_MASK     0x0c
-
-#define DSP_DTMF_DIGIT_TONE_CODE_0              0x07
-#define DSP_DTMF_DIGIT_TONE_CODE_1              0x00
-#define DSP_DTMF_DIGIT_TONE_CODE_2              0x04
-#define DSP_DTMF_DIGIT_TONE_CODE_3              0x08
-#define DSP_DTMF_DIGIT_TONE_CODE_4              0x01
-#define DSP_DTMF_DIGIT_TONE_CODE_5              0x05
-#define DSP_DTMF_DIGIT_TONE_CODE_6              0x09
-#define DSP_DTMF_DIGIT_TONE_CODE_7              0x02
-#define DSP_DTMF_DIGIT_TONE_CODE_8              0x06
-#define DSP_DTMF_DIGIT_TONE_CODE_9              0x0a
-#define DSP_DTMF_DIGIT_TONE_CODE_STAR           0x03
-#define DSP_DTMF_DIGIT_TONE_CODE_HASHMARK       0x0b
-#define DSP_DTMF_DIGIT_TONE_CODE_A              0x0c
-#define DSP_DTMF_DIGIT_TONE_CODE_B              0x0d
-#define DSP_DTMF_DIGIT_TONE_CODE_C              0x0e
-#define DSP_DTMF_DIGIT_TONE_CODE_D              0x0f
-
-
-#define DSP_UDATA_INDICATION_DTMF_DIGITS_SENT   16
-/*
-returns:
-  - none -
-  One indication will be sent for every request.
-*/
-
-
-#define DSP_UDATA_REQUEST_ENABLE_DTMF_RECEIVER  17
-/*
-parameters:
-  <word> tone duration (ms)
-  <word> gap duration (ms)
-*/
-typedef struct enable_dtmf_s {
-	__u16 tone;
-	__u16 gap;
-} enable_dtmf_s;
-
-#define DSP_UDATA_REQUEST_DISABLE_DTMF_RECEIVER 18
-/*
-parameters:
-  - none -
-*/
-
-#define DSP_UDATA_INDICATION_DTMF_DIGITS_RECEIVED 17
-/*
-returns:
-  <byte> digit 0 tone code
-  ...
-  <byte> digit n tone code
-*/
-
-#define DSP_DTMF_DIGITS_RECEIVED_HEADER_LENGTH  1
-
-
-#define DSP_UDATA_INDICATION_MODEM_CALLING_TONE 18
-/*
-returns:
-  - none -
-*/
-
-#define DSP_UDATA_INDICATION_FAX_CALLING_TONE   19
-/*
-returns:
-  - none -
-*/
-
-#define DSP_UDATA_INDICATION_ANSWER_TONE        20
-/*
-returns:
-  - none -
-*/
-
-/* ============= FAX ================ */
-
-#define EICON_FAXID_LEN 20
-
-typedef struct eicon_t30_s {
-  __u8          code;
-  __u8          rate;
-  __u8          resolution;
-  __u8          format;
-  __u8          pages_low;
-  __u8          pages_high;
-  __u8          atf;
-  __u8          control_bits_low;
-  __u8          control_bits_high;
-  __u8          feature_bits_low;
-  __u8          feature_bits_high;
-  __u8          universal_5;
-  __u8          universal_6;
-  __u8          universal_7;
-  __u8          station_id_len;
-  __u8          head_line_len;
-  __u8          station_id[EICON_FAXID_LEN];
-/* __u8          head_line[]; */
-} eicon_t30_s;
-
-        /* EDATA transmit messages */
-#define EDATA_T30_DIS       0x01
-#define EDATA_T30_FTT       0x02
-#define EDATA_T30_MCF       0x03
-
-        /* EDATA receive messages */
-#define EDATA_T30_DCS       0x81
-#define EDATA_T30_TRAIN_OK  0x82
-#define EDATA_T30_EOP       0x83
-#define EDATA_T30_MPS       0x84
-#define EDATA_T30_EOM       0x85
-#define EDATA_T30_DTC       0x86
-
-#define T30_FORMAT_SFF            0
-#define T30_FORMAT_ASCII          1
-#define T30_FORMAT_COUNT          2
-
-#define T30_CONTROL_BIT_DISABLE_FINE      0x0001
-#define T30_CONTROL_BIT_ENABLE_ECM        0x0002
-#define T30_CONTROL_BIT_ECM_64_BYTES      0x0004
-#define T30_CONTROL_BIT_ENABLE_2D_CODING  0x0008
-#define T30_CONTROL_BIT_ENABLE_T6_CODING  0x0010
-#define T30_CONTROL_BIT_ENABLE_UNCOMPR    0x0020
-#define T30_CONTROL_BIT_ACCEPT_POLLING    0x0040
-#define T30_CONTROL_BIT_REQUEST_POLLING   0x0080
-#define T30_CONTROL_BIT_MORE_DOCUMENTS    0x0100
-
-#define T30_CONTROL_BIT_ALL_FEATURES\
-  (T30_CONTROL_BIT_ENABLE_ECM | T30_CONTROL_BIT_ENABLE_2D_CODING |\
-   T30_CONTROL_BIT_ENABLE_T6_CODING | T30_CONTROL_BIT_ENABLE_UNCOMPR)
-
-#define T30_FEATURE_BIT_FINE              0x0001
-#define T30_FEATURE_BIT_ECM               0x0002
-#define T30_FEATURE_BIT_ECM_64_BYTES      0x0004
-#define T30_FEATURE_BIT_2D_CODING         0x0008
-#define T30_FEATURE_BIT_T6_CODING         0x0010
-#define T30_FEATURE_BIT_UNCOMPR_ENABLED   0x0020
-#define T30_FEATURE_BIT_POLLING           0x0040
-
-#define FAX_OBJECT_DOCU		1
-#define FAX_OBJECT_PAGE		2
-#define FAX_OBJECT_LINE		3
-
-#define T4_EOL			0x800
-#define T4_EOL_BITSIZE		12
-#define T4_EOL_DWORD		(T4_EOL << (32 - T4_EOL_BITSIZE))
-#define T4_EOL_MASK_DWORD	((__u32) -1 << (32 - T4_EOL_BITSIZE))
-
-#define SFF_LEN_FLD_SIZE	3
-
-#define _DLE_	0x10
-#define _ETX_	0x03
-
-typedef struct eicon_sff_dochead {
-	__u32	id		__attribute__ ((packed));
-	__u8	version		__attribute__ ((packed));
-	__u8	reserved1	__attribute__ ((packed));
-	__u16	userinfo	__attribute__ ((packed));
-	__u16	pagecount	__attribute__ ((packed));
-	__u16	off1pagehead	__attribute__ ((packed));
-	__u32	offnpagehead	__attribute__ ((packed));
-	__u32	offdocend	__attribute__ ((packed));
-} eicon_sff_dochead;
-
-typedef struct eicon_sff_pagehead {
-	__u8	pageheadid	__attribute__ ((packed));
-	__u8	pageheadlen	__attribute__ ((packed));
-	__u8	resvert		__attribute__ ((packed));
-	__u8	reshoriz	__attribute__ ((packed));
-	__u8	coding		__attribute__ ((packed));
-	__u8	reserved2	__attribute__ ((packed));
-	__u16	linelength	__attribute__ ((packed));
-	__u16	pagelength	__attribute__ ((packed));
-	__u32	offprevpage	__attribute__ ((packed));
-	__u32	offnextpage	__attribute__ ((packed));
-} eicon_sff_pagehead;
-
-#endif	/* E_IDI_H */
diff -Nru a/drivers/isdn/hardware/eicon/i4lididrv.c b/drivers/isdn/hardware/eicon/i4lididrv.c
--- a/drivers/isdn/hardware/eicon/i4lididrv.c	Sat Apr  3 19:38:56 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1418 +0,0 @@
-/* $Id: i4lididrv.c,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
- *
- * ISDN interface module for Eicon active cards.
- * I4L - IDI Interface
- * 
- * Copyright 1998-2000 by Armin Schindler (mac@melware.de) 
- * Copyright 1999-2002 Cytronics & Melware (info@melware.de)
- * 
- * Thanks to	Deutsche Mailbox Saar-Lor-Lux GmbH
- *		for sponsoring and testing fax
- *		capabilities with Diva Server cards.
- *		(dor@deutschemailbox.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/vmalloc.h>
-
-#include "i4lididrv.h"
-#include <linux/smp_lock.h>
-#include "divasync.h"
-
-#include "../avmb1/capicmd.h"  /* this should be moved in a common place */
-
-#define INCLUDE_INLINE_FUNCS
-
-static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
-                                                     start of card-list   */
-
-static char *DRIVERNAME = "Eicon Diva - native I4L Interface driver (http://www.melware.net)";
-static char *DRIVERLNAME = "diva2i4l";
-static char *DRIVERRELEASE = "2.0";
-static char *eicon_revision = "$Revision: 1.1.2.2 $";
-extern char *eicon_idi_revision;
-
-#define EICON_CTRL_VERSION 2
-
-ulong DebugVar;
-
-static spinlock_t status_lock;
-static spinlock_t ll_lock;
-
-#define MAX_DESCRIPTORS  32
-extern void DIVA_DIDD_Read(DESCRIPTOR *, int);
-
-static dword notify_handle;
-static DESCRIPTOR DAdapter;
-static DESCRIPTOR MAdapter;
-
-/* Parameter to be set by insmod */
-static char *id  = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-static int debug = 1;
-
-MODULE_DESCRIPTION(             "ISDN4Linux Interface for Eicon active card driver");
-MODULE_AUTHOR(                  "Armin Schindler");
-MODULE_SUPPORTED_DEVICE(        "ISDN subsystem and Eicon active card driver");
-MODULE_PARM_DESC(id,   		"ID-String for ISDN4Linux");
-MODULE_PARM(id,           	"s");
-MODULE_PARM_DESC(debug,		"Initial debug value");
-MODULE_PARM(debug,           	"i");
-MODULE_LICENSE("GPL");
-
-void no_printf (unsigned char * x ,...)
-{
-  /* dummy debug function */
-}
-DIVA_DI_PRINTF dprintf = no_printf;
-
-#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
-#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)
-#include "debuglib.c"
-
-static char *
-eicon_getrev(const char *revision)
-{
-	char *rev;
-	char *p;
-	if ((p = strchr(revision, ':'))) {
-		rev = p + 2;
-		p = strchr(rev, '$');
-		*--p = 0;
-	} else rev = "1.0";
-	return rev;
-
-}
-
-static void
-stop_dbg(void)
-{
-		DbgDeregister();
-		memset(&MAdapter, 0, sizeof(MAdapter));
-		dprintf = no_printf;
-}
-
-static eicon_chan *
-find_channel(eicon_card *card, int channel)
-{
-	if ((channel >= 0) && (channel < card->nchannels))
-        	return &(card->bch[channel]);
-	eicon_log(card, 1, "%s: Invalid channel %d\n", DRIVERLNAME, channel);
-	return NULL;
-}
-
-static void
-eicon_rx_request(struct eicon_card *card)
-{
-	struct sk_buff *skb, *skb2, *skb_new;
-	eicon_IND *ind, *ind2, *ind_new;
-	eicon_chan *chan;
-
-	if (!card) {
-		eicon_log(card, 1, "%s: NULL card in rcv_dispatch !\n", DRIVERLNAME);
-		return;
-	}
-
-	while((skb = skb_dequeue(&card->rcvq))) {
-		ind = (eicon_IND *)skb->data;
-
-		if ((chan = card->IdTable[ind->IndId]) == NULL) {
-			if (DebugVar & 1) {
-				switch(ind->Ind) {
-					case N_DISC_ACK:
-						/* doesn't matter if this happens */
-						break;
-					default:
-						eicon_log(card, 1, "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId);
-						eicon_log(card, 1, "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n",
-						ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
-				}
-			}
-			dev_kfree_skb(skb);
-			continue;
-		}
-
-		if (chan->e.complete) { /* check for rec-buffer chaining */
-			if (ind->MLength == ind->RBuffer.length) {
-				chan->e.complete = 1;
-				idi_handle_ind(card, skb);
-				continue;
-			}
-			else {
-				chan->e.complete = 0;
-				ind->Ind = ind->MInd;
-				skb_queue_tail(&chan->e.R, skb);
-				continue;
-			}
-		}
-		else {
-			if (!(skb2 = skb_dequeue(&chan->e.R))) {
-				chan->e.complete = 1;
-				eicon_log(card, 1, "%s: buffer incomplete, but 0 in queue\n", DRIVERLNAME);
-				dev_kfree_skb(skb);
-				continue;
-			}
-			ind2 = (eicon_IND *)skb2->data;
-			skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length),
-				GFP_ATOMIC);
-			if (!skb_new) {
-			eicon_log(card, 1, "%s: skb_alloc failed in rcv_dispatch()\n", DRIVERLNAME);
-				dev_kfree_skb(skb);
-				dev_kfree_skb(skb2);
-				continue;
-			}
-			ind_new = (eicon_IND *)skb_put(skb_new,
-				((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length));
-			ind_new->Ind = ind2->Ind;
-			ind_new->IndId = ind2->IndId;
-			ind_new->IndCh = ind2->IndCh;
-			ind_new->MInd = ind2->MInd;
-			ind_new->MLength = ind2->MLength;
-			ind_new->RBuffer.length = ind2->RBuffer.length + ind->RBuffer.length;
-			memcpy(&ind_new->RBuffer.P, &ind2->RBuffer.P, ind2->RBuffer.length);
-			memcpy((&ind_new->RBuffer.P)+ind2->RBuffer.length, &ind->RBuffer.P, ind->RBuffer.length);
-			dev_kfree_skb(skb);
-			dev_kfree_skb(skb2);
-			if (ind->MLength == ind->RBuffer.length) {
-				chan->e.complete = 2;
-				idi_handle_ind(card, skb_new);
-				continue;
-			}
-			else {
-				chan->e.complete = 0;
-				skb_queue_tail(&chan->e.R, skb_new);
-				continue;
-			}
-		}
-	}
-}
-
-static void
-eicon_ack_request(struct eicon_card *card)
-{
-	struct sk_buff *skb;
-
-	if (!card) {
-		eicon_log(card, 1, "%s: NULL card in ack_dispatch!\n", DRIVERLNAME);
-		return;
-	}
-	while((skb = skb_dequeue(&card->rackq))) {
-		idi_handle_ack(card, skb);
-	}
-}
-
-/*
- *  IDI-Callback function
- */
-static void
-eicon_idi_callback(ENTITY *de)
-{
-	eicon_card *ccard = (eicon_card *)de->R;
-	struct sk_buff *skb;
-	eicon_RC *ack;
-	eicon_IND *ind;
-	int len = 0;
-
-	if (de->complete == 255) {
-		/* Return Code */
-		skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
-		if (!skb) {
-			eicon_log(ccard, 1, "%s: skb_alloc failed in _idi_callback()\n", DRIVERLNAME);
-		} else {
-			ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
-			ack->Rc = de->Rc;
-			if (de->Rc == ASSIGN_OK) {
-				ack->RcId = de->Id;
-				de->user[1] = de->Id;
-			} else {
-				ack->RcId = de->user[1];
-			}
-			ack->RcCh = de->RcCh;
-			ack->Reference = de->user[0];
-			skb_queue_tail(&ccard->rackq, skb);
-			eicon_ack_request(ccard);
-			eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n",
-				de->user[0], de->Rc, ack->RcId, de->RLength, de->complete);
-			DBG_TRC(("idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x",
-				de->user[0], de->Rc, ack->RcId, de->RLength, de->complete))
-	                de->Rc = 0;
-		}
-	} else {
-		/* Indication */
-		if (de->complete) {
-			len = de->RLength;
-		} else {
-			len = 270;
-			if (de->RLength <= 270)
-				eicon_log(ccard, 1, "idi_cbk: ind not complete but <= 270\n");
-		}
-		skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
-		if (!skb) {
-			eicon_log(ccard, 1, "%s: skb_alloc failed in _idi_callback()\n", DRIVERLNAME);
-		} else {
-			ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
-			ind->Ind = de->Ind;
-			ind->IndId = de->user[1];
-			ind->IndCh = de->IndCh;
-			ind->MInd  = de->Ind;
-			ind->RBuffer.length = len;
-			ind->MLength = de->RLength;
-			memcpy(&ind->RBuffer.P, &de->RBuffer->P, len);
-			skb_queue_tail(&ccard->rcvq, skb);
-			eicon_rx_request(ccard);
-			eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n",
-				de->user[0], de->Ind, ind->IndId, de->RLength, de->complete);
-			DBG_TRC(("idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x",
-				de->user[0], de->Ind, ind->IndId, de->RLength, de->complete))
-	                de->Ind = 0;
-		}
-	}
-	de->RNum = 0;
-	de->RNR = 0;
-    eicon_tx_request(ccard);
-}
-
-/*
-**  Kernel thread to prevent in_interrupt
-*/
-static DECLARE_TASK_QUEUE(tq_divad);
-static struct semaphore diva_thread_sem;
-static struct semaphore diva_thread_end;
-static int divad_pid = -1;
-static int divad_thread(void * data);
-static void diva_tx(void *data);
-static atomic_t thread_running;
-
-static void __init
-diva_init_thread(void)
-{
-  int pid = 0;
-
-  pid = kernel_thread(divad_thread, NULL, CLONE_KERNEL);
-  if (pid >= 0) {
-       divad_pid = pid;
-  }
-}
-
-static int
-divad_thread(void * data)
-{
-  atomic_inc(&thread_running);
-  if (atomic_read(&thread_running) > 1) {
-      printk(KERN_WARNING"%s: thread already running\n", DRIVERLNAME);
-      return(0);
-  }
-
-  printk(KERN_INFO "%s: thread started with pid %d\n", DRIVERLNAME, current->pid);
-  exit_mm(current);
-  exit_files(current);
-  exit_fs(current);
-
-  /* Set to RealTime */
-  current->policy = SCHED_FIFO;
-  current->rt_priority = 33;
-
-  strcpy(current->comm, "kdiva2i4ld");
-
-  for(;;) {
-    down_interruptible(&diva_thread_sem);
-    if(!(atomic_read(&thread_running)))
-      break;
-    if(signal_pending(current)) {
-         flush_signals(current);
-    } else {
-         run_task_queue(&tq_divad);
-    }
-  }
-  up(&diva_thread_end);
-  divad_pid = -1;
-  return 0;
-}
-
-static void
-stop_diva_thread(void)
-{
-    if (divad_pid >= 0) {
-         atomic_set(&thread_running, 0);
-         up(&diva_thread_sem);
-         down_interruptible(&diva_thread_end);
-    }
-}
-
-void
-eicon_tx_request(struct eicon_card *card)
-{
-  card->tq.routine = diva_tx;
-  card->tq.data = (void *)card;
-  queue_task(&card->tq, &tq_divad);
-  up(&diva_thread_sem);
-}
-
-static void
-diva_tx(void *data)
-{
-        struct eicon_card *card = (eicon_card *) data;
-	struct sk_buff *skb;
-	struct sk_buff *skb2;
-	eicon_chan *chan;
-	eicon_chan_ptr *chan2;
-	eicon_REQ *reqbuf = 0;
-	int ReqCount = 0;
-	int tmpid = 0;
-	int quloop = 1;
-	int dlev = 0;
-	ENTITY *ep = 0;
-
-        if (!card) {
-                eicon_log(card, 1, "%s: NULL card in transmit !\n", DRIVERLNAME);
-                return;
-        }
-
-	ReqCount = 0;
-	if (!(skb2 = skb_dequeue(&card->sndq)))
-		quloop = 0;
-	while(quloop) {
-		chan2 = (eicon_chan_ptr *)skb2->data;
-		chan = chan2->ptr;
-		if (!chan->e.busy) {
-		 if((skb = skb_dequeue(&chan->e.X))) {
-
-		  reqbuf = (eicon_REQ *)skb->data;
-		  if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
-			eicon_log(card, 16, "%s: transmit: error Id=0 on %d (Net)\n", DRIVERLNAME, chan->No);
-		  } else {
-			dlev = 160;
-			if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
-
-				if (!reqbuf->Reference) { /* Signal Layer */
-					ep = &chan->de;
-					tmpid = chan->e.D3Id;
-					chan->e.ReqCh = 0;
-				}
-				else {                  /* Net Layer */
-					ep = &chan->be;
-					tmpid = chan->e.B2Id;
-					chan->e.ReqCh = 1;
-					if (((reqbuf->Req & 0x0f) == 0x08) ||
-					    ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
-						chan->waitq = reqbuf->XBuffer.length;
-						chan->waitpq += reqbuf->XBuffer.length;
-						dlev = 128;
-					}
-				}
-
-			} else {        /* It is an ASSIGN */
-				if (!reqbuf->Reference)
-					ep = &chan->de;
-				else
-					ep = &chan->be;
-				ep->Id = reqbuf->ReqId;
-				tmpid = reqbuf->ReqId;
-
-				if (!reqbuf->Reference)
-					chan->e.ReqCh = 0;
-				else
-					chan->e.ReqCh = 1;
-			}
-
-			chan->e.ref = chan->No;
-			chan->e.Req = reqbuf->Req;
-			ReqCount++;
-			if (ep) {
-				ep->callback = eicon_idi_callback;
-				ep->R = (BUFFERS *)card;
-				ep->user[0] = (word)chan->No;
-				ep->user[1] = (word)tmpid;
-				ep->XNum = 1;
-				ep->RNum = 0;
-				ep->RNR = 0;
-				ep->Rc = 0;
-				ep->Ind = 0;
-				ep->X->PLength = reqbuf->XBuffer.length;
-				memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
-				ep->ReqCh = reqbuf->ReqCh;
-				ep->Req = reqbuf->Req;
-			}
-			chan->e.busy = 1;
-			eicon_log(card, dlev, "idi: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n",
-				reqbuf->Req, tmpid,
-				reqbuf->ReqCh, reqbuf->XBuffer.length,
-				chan->e.ref);
-			if (ep) {
-				card->d.request(ep);
-				if (ep->Rc)
-					eicon_idi_callback(ep);
-			}
-		  }
-		  dev_kfree_skb(skb);
-		 }
-		 dev_kfree_skb(skb2);
-		}
-		else {
-			skb_queue_tail(&card->sackq, skb2);
-			eicon_log(card, 128, "%s: transmit: busy chan %d\n", DRIVERLNAME, chan->No);
-		}
-		if (!(skb2 = skb_dequeue(&card->sndq)))
-			quloop = 0;
-	}
-	while((skb = skb_dequeue(&card->sackq))) {
-		skb_queue_tail(&card->sndq, skb);
-	}
-}
-
-static int
-eicon_command(eicon_card * card, isdn_ctrl * c)
-{
-        ulong a;
-        eicon_chan *chan;
-	isdn_ctrl cmd;
-	int ret = 0;
-
-	eicon_log(card, 16, "%s_cmd 0x%x with arg 0x%lx (0x%lx)\n", DRIVERLNAME,
-		c->command, c->arg, (ulong) *c->parm.num);
-
-        switch (c->command) {
-		case ISDN_CMD_IOCTL:
-			memcpy(&a, c->parm.num, sizeof(ulong));
-			switch (c->arg) {
-				case EICON_IOCTL_GETVER:
-					return(EICON_CTRL_VERSION);
-				case EICON_IOCTL_MANIF:
-					if (!card->flags & EICON_FLAGS_RUNNING)
-						return -ENODEV;
-					if (!card->d.features & DI_MANAGE)
-						return -ENODEV;
-					ret = eicon_idi_manage(
-						card, 
-						(eicon_manifbuf *)a);
-					return ret;
-
-				case EICON_IOCTL_GETXLOG:
-					return -ENODEV;
-				case EICON_IOCTL_DEBUGVAR:
-					DebugVar = a;
-					eicon_log(card, 1, "%s: Debug Value set to %ld\n", DRIVERLNAME, DebugVar);
-					return 0;
-				case EICON_IOCTL_LOADPCI:
-					eicon_log(card, 1, "%s: Wrong version of load-utility,\n", DRIVERLNAME);
-					eicon_log(card, 1, "%s: re-compile eiconctrl !\n", DRIVERLNAME);
-					eicon_log(card, 1, "%s: Maybe update of utility is necessary !\n", DRIVERLNAME);
-					return -EINVAL;
-				default:	
-					return -EINVAL;
-			}
-			break;
-		case ISDN_CMD_DIAL:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) {
-				eicon_log(card, 1, "%s: Dial on channel %d with state %d\n", DRIVERLNAME,
-					chan->No, chan->fsm_state);
-				return -EBUSY;
-			}
-			chan->fsm_state = EICON_STATE_OCALL;
-			
-			ret = idi_connect_req(card, chan, c->parm.setup.phone,
-						     c->parm.setup.eazmsn,
-						     c->parm.setup.si1,
-						     c->parm.setup.si2);
-			if (ret) {
-				cmd.driver = card->myid;
-				cmd.command = ISDN_STAT_DHUP;
-				cmd.arg &= 0x1f;
-				card->interface.statcallb(&cmd);
-			}
-			return ret;
-		case ISDN_CMD_ACCEPTD:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			if (chan->fsm_state == EICON_STATE_ICALL) { 
-				idi_connect_res(card, chan);
-			}
-			return 0;
-		case ISDN_CMD_ACCEPTB:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			return 0;
-		case ISDN_CMD_HANGUP:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			idi_hangup(card, chan);
-			return 0;
-		case ISDN_CMD_SETEAZ:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			chan->eazmask = 0x3ff;
-			eicon_idi_listen_req(card, chan);
-			return 0;
-		case ISDN_CMD_CLREAZ:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			chan->eazmask = 0;
-			eicon_idi_listen_req(card, chan);
-			return 0;
-		case ISDN_CMD_SETL2:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			chan->l2prot = (c->arg >> 8);
-                        memcpy(chan->a_para, c->parm.aux.para, sizeof(chan->a_para));
-			return 0;
-		case ISDN_CMD_SETL3:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			chan->l3prot = (c->arg >> 8);
-#ifdef CONFIG_ISDN_TTY_FAX
-			if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) {
-				chan->fax = c->parm.fax;
-				eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax);
-			}
-#endif
-			return 0;
-#ifdef CONFIG_ISDN_TTY_FAX
-		case ISDN_CMD_FAXCMD:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			if (!chan->fax)
-				break;
-			idi_fax_cmd(card, chan);
-			return 0;
-#endif
-		case ISDN_CMD_AUDIO:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num);
-			return 0;
-		case CAPI_PUT_MESSAGE:
-			if (!card->flags & EICON_FLAGS_RUNNING)
-				return -ENODEV;
-			if (!(chan = find_channel(card, c->arg & 0x1f)))
-				break;
-			if (c->parm.cmsg.Length < 8)
-				break;
-			switch(c->parm.cmsg.Command) {
-				case CAPI_FACILITY:
-					if (c->parm.cmsg.Subcommand == CAPI_REQ)
-						return(capipmsg(card, chan, &c->parm.cmsg));
-					break;
-				case CAPI_MANUFACTURER:
-				default:
-					break;
-			}
-			return 0;
-        }
-	
-        return -EINVAL;
-}
-
-static int
-find_free_number(void)
-{
-  int num = 0;
-  char cid[40];
-  eicon_card *p;
-  ulong flags;
-
-  spin_lock_irqsave(&ll_lock, flags);
-  while(num < 100) {
-    sprintf(cid, "%s%d", id, num);
-    num++;
-    p = cards;
-    while (p) {
-      if (!strcmp(p->regname, cid))
-        break;
-      p = p->next;
-    }
-		if (p)
-		{
-	    spin_unlock_irqrestore(&ll_lock, flags);
-  	  return(num - 1);
-		}
-  }
-  spin_unlock_irqrestore(&ll_lock, flags);
-  return(999);
-}
-
-/*
- * Find card with given driverId
- */
-static inline eicon_card *
-eicon_findcard(int driverid)
-{
-  eicon_card *p;
-  ulong flags;
-
-  spin_lock_irqsave(&ll_lock, flags);
-  p = cards;
-  while (p) {
-    if (p->myid == driverid) {
-      spin_unlock_irqrestore(&ll_lock, flags);
-      return p;
-    }
-    p = p->next;
-  }
-  spin_unlock_irqrestore(&ll_lock, flags);
-  return (eicon_card *) 0;
-}
-
-/*
- * Wrapper functions for interface to linklevel
- */
-static int
-if_command(isdn_ctrl * c)
-{
-        eicon_card *card = eicon_findcard(c->driver);
-
-        if (card)
-                return (eicon_command(card, c));
-        printk(KERN_ERR
-             "%s: if_command %d called with invalid driverId %d!\n", DRIVERLNAME,
-               c->command, c->driver);
-        return -ENODEV;
-}
-
-static int
-if_writecmd(const u_char * buf, int len, int user, int id, int channel)
-{
-	/* Not used */
-        return (len);
-}
-
-static int
-if_readstatus(u_char * buf, int len, int user, int id, int channel)
-{
-  int count = 0;
-  int cnt = 0;
-  u_char *p = buf;
-  struct sk_buff *skb;
-  ulong flags;
-
-        eicon_card *card = eicon_findcard(id);
-	
-        if (card) {
-                if (!card->flags & EICON_FLAGS_RUNNING)
-                        return -ENODEV;
-	
-		spin_lock_irqsave(&status_lock, flags);
-		while((skb = skb_dequeue(&card->statq))) {
-
-			if ((skb->len + count) > len)
-				cnt = len - count;
-			else
-				cnt = skb->len;
-
-			if (user)
-				copy_to_user(p, skb->data, cnt);
-			else
-				memcpy(p, skb->data, cnt);
-
-			count += cnt;
-			p += cnt;
-
-			if (cnt == skb->len) {
-				dev_kfree_skb(skb);
-				if (card->statq_entries > 0)
-					card->statq_entries--;
-			} else {
-				skb_pull(skb, cnt);
-				skb_queue_head(&card->statq, skb);
-				spin_unlock_irqrestore(&status_lock, flags);
-				return count;
-			}
-		}
-		card->statq_entries = 0;
-		spin_unlock_irqrestore(&status_lock, flags);
-		return count;
-        }
-        printk(KERN_ERR
-               "%s: if_readstatus called with invalid driverId!\n", DRIVERLNAME);
-        return 0;
-}
-
-static int
-if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
-{
-        eicon_card *card = eicon_findcard(id);
-	eicon_chan *chan;
-	int ret = 0;
-	int len;
-
-	len = skb->len;
-
-        if (card) {
-                if (!card->flags & EICON_FLAGS_RUNNING)
-                        return -ENODEV;
-        	if (!(chan = find_channel(card, channel)))
-			return -ENODEV;
-
-		if (chan->fsm_state == EICON_STATE_ACTIVE) {
-#ifdef CONFIG_ISDN_TTY_FAX
-			if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-				if ((ret = idi_faxdata_send(card, chan, skb)) > 0)
-					ret = len;
-			}
-			else
-#endif
-				ret = idi_send_data(card, chan, ack, skb, 1, 1);
-			return (ret);
-		} else {
-			return -ENODEV;
-		}
-        }
-        printk(KERN_ERR
-               "%s: if_sendbuf called with invalid driverId!\n", DRIVERLNAME);
-        return -ENODEV;
-}
-
-/* jiftime() copied from HiSax */
-static inline int jiftime(char *s, long mark)
-{
-        s += 8;
-
-        *s-- = '\0';
-        *s-- = mark % 10 + '0';
-        mark /= 10;
-        *s-- = mark % 10 + '0';
-        mark /= 10;
-        *s-- = '.';
-        *s-- = mark % 10 + '0';
-        mark /= 10;
-        *s-- = mark % 6 + '0';
-        mark /= 6;
-        *s-- = ':';
-        *s-- = mark % 10 + '0';
-        mark /= 10;
-        *s-- = mark % 10 + '0';
-        return(8);
-}
-
-void
-eicon_putstatus(eicon_card * card, char * buf)
-{
-  int count;
-  isdn_ctrl cmd;
-  u_char *p;
-  struct sk_buff *skb;
-  ulong flags;
-
-	if (!card) {
-		if (!(card = cards))
-			return;
-	}
-
-	spin_lock_irqsave(&status_lock, flags);
-	count = strlen(buf);
-	skb = alloc_skb(count, GFP_ATOMIC);
-	if (!skb) {
-		spin_unlock_irqrestore(&status_lock, flags);
-		printk(KERN_ERR "%s: could not alloc skb in putstatus\n", DRIVERLNAME);
-		return;
-	}
-	p = skb_put(skb, count);
-	memcpy(p, buf, count);
-
-	skb_queue_tail(&card->statq, skb);
-
-	if (card->statq_entries >= MAX_STATUS_BUFFER) {
-		if ((skb = skb_dequeue(&card->statq))) {
-			count -= skb->len;
-			dev_kfree_skb(skb);
-		} else
-			count = 0;
-	} else
-		card->statq_entries++;
-
-	spin_unlock_irqrestore(&status_lock, flags);
-        if (count) {
-                cmd.command = ISDN_STAT_STAVAIL;
-                cmd.driver = card->myid;
-                cmd.arg = count;
-		card->interface.statcallb(&cmd);
-        }
-}
-
-/*
- * Debug and Log 
- */
-void
-eicon_log(eicon_card * card, int level, const char *fmt, ...)
-{
-	va_list args;
-	char Line[160];
-	u_char *p;
-
-
-	if ((DebugVar & level) || (DebugVar & 256)) {
-		va_start(args, fmt);
-
-		if (DebugVar & level) {
-			if (DebugVar & 256) {
-				/* log-buffer */
-				p = Line;
-				p += jiftime(p, jiffies);
-				*p++ = 32;
-				p += vsprintf(p, fmt, args);
-				*p = 0;	
-				eicon_putstatus(card, Line);
-			} else {
-				/* printk, syslogd */
-				vsprintf(Line, fmt, args);
-				printk(KERN_DEBUG "%s", Line);
-			}
-		}
-
-		va_end(args);
-	}
-}
-
-
-/*
- * Allocate a new card-struct, initialize it
- * link it into cards-list.
- */
-static void
-eicon_alloccard(DESCRIPTOR *d)
-{
-  int j;
-  char cid[40];
-  eicon_card *card;
-  ulong flags;
-
-	sprintf(cid, "%s%d", id, find_free_number());
-	if (!(card = (eicon_card *) kmalloc(sizeof(eicon_card), GFP_KERNEL))) {
-		eicon_log(card, 1,
-		       "%s: (%s) Could not allocate card-struct.\n", DRIVERLNAME, cid);
-		return;
-	}
-	memset((char *) card, 0, sizeof(eicon_card));
-	skb_queue_head_init(&card->sndq);
-	skb_queue_head_init(&card->rcvq);
-	skb_queue_head_init(&card->rackq);
-	skb_queue_head_init(&card->sackq);
-	skb_queue_head_init(&card->statq);
-	card->statq_entries = 0;
-	card->interface.owner = THIS_MODULE;
-	card->interface.maxbufsize = 4000;
-	card->interface.command = if_command;
-	card->interface.writebuf_skb = if_sendbuf;
-	card->interface.writecmd = if_writecmd;
-	card->interface.readstat = if_readstatus;
-	card->interface.features =
-		ISDN_FEATURE_L2_X75I |
-		ISDN_FEATURE_L2_HDLC |
-		ISDN_FEATURE_L2_TRANS |
-		ISDN_FEATURE_L3_TRANS |
-		ISDN_FEATURE_L3_TRANSDSP |
-		ISDN_FEATURE_P_UNKNOWN;
-	card->interface.hl_hdrlen = 20;
-	card->ptype = ISDN_PTYPE_UNKNOWN;
-	strcpy(card->interface.id, cid);
-	card->myid = -1;
-	card->type = d->type;
-
-	if (d->features & (DI_FAX3 | DI_EXTD_FAX))
-		card->interface.features |= (ISDN_FEATURE_L2_FAX | ISDN_FEATURE_L3_FCLASS2);
-	if (d->features & DI_MODEM)
-		card->interface.features |= ISDN_FEATURE_L2_MODEM;
-	if (d->features & DI_V110)
-		card->interface.features |= (ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038);
-
-	card->flags = 0;
-	card->nchannels = d->channels;
-	card->interface.channels = d->channels;
-	if (!(card->bch = (eicon_chan *) vmalloc(sizeof(eicon_chan) * (card->nchannels + 1)))) {
-		eicon_log(card, 1,
-		       "%s: (%s) Could not allocate bch-struct.\n", DRIVERLNAME, cid);
-		kfree(card);
-		return;
-	}
-	for (j=0; j< (card->nchannels + 1); j++) {
-		memset((char *)&card->bch[j], 0, sizeof(eicon_chan));
-		card->bch[j].statectrl = 0;
-		card->bch[j].l2prot = ISDN_PROTO_L2_X75I;
-		card->bch[j].l3prot = ISDN_PROTO_L3_TRANS;
-		card->bch[j].e.D3Id = 0;
-		card->bch[j].e.B2Id = 0;
-		card->bch[j].e.Req = 0;
-		card->bch[j].No = j;
-		card->bch[j].tskb1 = NULL;
-		card->bch[j].tskb2 = NULL;
-		skb_queue_head_init(&card->bch[j].e.X);
-		skb_queue_head_init(&card->bch[j].e.R);
-	}
-
-	if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2
-						 , GFP_KERNEL))) {
-		eicon_log(card, 1,
-		       "%s: (%s) Could not allocate DBUFFER-struct.\n", DRIVERLNAME, cid);
-		kfree(card);
-		vfree(card->bch);
-		return;
-	}
-	if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
-		eicon_log(card, 1,
-		       "%s: (%s) Could not allocate BUFFERS-struct.\n", DRIVERLNAME, cid);
-		kfree(card);
-		vfree(card->bch);
-		kfree(card->dbuf);
-		return;
-	}
-	if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
-		eicon_log(card, 1,
-		       "%s: (%s) Could not allocate BUFFERSP-struct.\n", DRIVERLNAME, cid);
-		kfree(card);
-		vfree(card->bch);
-		kfree(card->dbuf);
-		kfree(card->sbuf);
-		return;
-	}
-	for (j=0; j< (card->nchannels + 1); j++) {
-		memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER));
-		card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j];
-		memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
-		card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)];
-
-		memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS));
-		card->bch[j].de.X = (BUFFERS *)&card->sbuf[j];
-		memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
-		card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)];
-
-		memset((char *)&card->sbufp[j], 0, 270);
-		card->bch[j].de.X->P = (char *)&card->sbufp[j * 270];
-		memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270);
-		card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270];
-	}
-	memcpy(&card->d, d, sizeof(*d)); /* DESCRIPTOR entries */
-
-	/* initializing some variables */
-	card->lock = SPIN_LOCK_UNLOCKED;
-	card->ReadyInt = 0;
-
-	for(j = 0; j < 256; j++)
-		card->IdTable[j] = NULL;
-
-	for(j = 0; j < (card->d.channels + 1); j++) {
-		card->bch[j].e.busy = 0;
-		card->bch[j].e.D3Id = 0;
-		card->bch[j].e.B2Id = 0;
-		card->bch[j].e.ref = 0;
-		card->bch[j].e.Req = 0;
-		card->bch[j].e.complete = 1;
-		card->bch[j].fsm_state = EICON_STATE_NULL;
-	}
-	printk(KERN_INFO "%s: registered card '%s' with %d channels\n",
-		DRIVERLNAME, cid, d->channels);
-
-  spin_lock_irqsave(&ll_lock, flags);
-	card->next = cards;
-	cards = card;
-  spin_unlock_irqrestore(&ll_lock, flags);
-}
-
-/*
- * register card at linklevel
- */
-static int
-eicon_registercard(eicon_card * card)
-{
-	isdn_ctrl cmd;
-
-        if (!register_isdn(&card->interface)) {
-                printk(KERN_WARNING
-                       "%s: Unable to register %s\n", DRIVERLNAME,
-                       card->interface.id);
-                return -1;
-        }
-        card->myid = card->interface.channels;
-        sprintf(card->regname, "%s", card->interface.id);
-
-	/* after register we start it */
-	card->flags |= EICON_FLAGS_LOADED;
-	card->flags |= EICON_FLAGS_RUNNING;
-	cmd.command = ISDN_STAT_RUN;
-	cmd.driver = card->myid;
-	cmd.arg = 0;
-	card->interface.statcallb(&cmd);
-
-        return 0;
-}
-
-static void 
-unregister_card(eicon_card * card, int rme)
-{
-  int count;
-  int channel;
-  isdn_ctrl cmd;
-  eicon_chan *chan;
-
-  if(rme) {
-      /* before unload we need to remove the signal entity */
-      for(channel = 0; channel < card->nchannels; channel++)
-        {
-		chan = &(card->bch[channel]);
-                if (chan->e.D3Id) {
-                        idi_do_req(card, chan, REMOVE, 0);
-			count = 100;
-			while(count--) {
-				if (!chan->e.D3Id)
-					break;
-				SLEEP(2);
-			}
-			if (!count)
-				printk(KERN_WARNING"%s: ch:%d unlink to diva module not successful !\n",
-					DRIVERLNAME, chan->No);
-		}
-        }
-  }
-
-  cmd.command = ISDN_STAT_UNLOAD;
-  cmd.driver = card->myid;
-  card->interface.statcallb(&cmd);
-  DBG_TRC(("channel entities freed"));
-}
-
-static void
-eicon_freecard(eicon_card *card) {
-	int i;
-
-	for(i = 0; i < (card->nchannels + 1); i++) {
-		skb_queue_purge(&card->bch[i].e.X);
-		skb_queue_purge(&card->bch[i].e.R);
-	}
-	skb_queue_purge(&card->sndq);
-	skb_queue_purge(&card->rcvq);
-	skb_queue_purge(&card->rackq);
-	skb_queue_purge(&card->sackq);
-	skb_queue_purge(&card->statq);
-
-	kfree(card->sbufp);
-	kfree(card->sbuf);
-	kfree(card->dbuf);
-	vfree(card->bch);
-	kfree(card);
-        DBG_TRC(("card structures freed"));
-}
-
-static int
-eicon_addcard(DESCRIPTOR *d)
-{
-  eicon_card *p;
-  eicon_card *q = NULL;
-  int registered;
-  int added = 0;
-  int failed = 0;
-  ulong flags;
-
-	eicon_alloccard(d);
-        p = cards;
-        while (p) {
-		registered = 0;
-		if (!p->interface.statcallb) {
-			/* Not yet registered.
-			 * Try to register and activate it.
-			 */
-			added++;
-			if (!eicon_registercard(p))
-				registered = 1;
-		} else {
-			/* Card already registered */
-			registered = 1;
-		}
-
-                if (registered) {
-			/* Init OK, next card ... */
-                        spin_lock_irqsave(&ll_lock, flags);
-                        q = p;
-                        p = p->next;
-                        spin_unlock_irqrestore(&ll_lock, flags);
-                } else {
-                        /* registering failed, remove card from list, free memory */
-                        printk(KERN_ERR
-                               "%s: Initialization of %s failed\n", DRIVERLNAME,
-                               p->interface.id);
-                        spin_lock_irqsave(&ll_lock, flags);
-                        if (q) {
-                                q->next = p->next;
-                                eicon_freecard(p);
-                                p = q->next;
-                        } else {
-                                cards = p->next;
-                                eicon_freecard(p);
-                                p = cards;
-                        }
-                        spin_unlock_irqrestore(&ll_lock, flags);
-			failed++;
-                }
-	}
-        return (added - failed);
-}
-
-static void *
-didd_callback(void *context, DESCRIPTOR* adapter, int removal)
-{
-  eicon_card *cp = NULL, *lastcp = NULL;
-  ulong flags;
-
-  if (adapter->type == IDI_DADAPTER)
-  {
-    printk(KERN_ERR "%s: Change in DAdapter ? Oops ?.\n", DRIVERLNAME);
-    DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
-    return(NULL);
-  }
-  else if (adapter->type == IDI_DIMAINT)
-  {
-    if (removal)
-    {
-				stop_dbg();
-    }
-    else
-    {
-      memcpy(&MAdapter, adapter, sizeof(MAdapter));
-      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
-      DbgRegister("I4L", DRIVERRELEASE, DBG_DEFAULT);
-    }
-  }
-  else if ((adapter->type > 0) &&
-           (adapter->type < 16))
-  {  /* IDI Adapter */
-    if (removal)
-    {
-      spin_lock_irqsave(&ll_lock, flags);
-      lastcp = cp = cards;
-      while (cp) {
-        if (cp->d.request == adapter->request)
-        {
-          spin_unlock_irqrestore(&ll_lock, flags);
-          DBG_LOG(("remove adapter from list"));
-          unregister_card(cp, 0);
-          spin_lock_irqsave(&ll_lock, flags);
-          if (cp == lastcp)
-            cards = cp->next;
-          else
-            lastcp->next = cp->next;
-          eicon_freecard(cp);
-          break;
-        }
-        lastcp = cp;
-        cp = cp->next;
-      }
-      spin_unlock_irqrestore(&ll_lock, flags);
-    }
-    else
-    {
-      if (adapter->channels) {
-        DBG_LOG(("add adapter to list"));
-        eicon_addcard(adapter);
-      }
-    }
-  }
-  return(NULL);
-}
-
-static int __init
-connect_didd(void)
-{
-  int x = 0;
-  int dadapter = 0;
-  IDI_SYNC_REQ req;
-  DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];
-
-  DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));
-
-  for (x = 0; x < MAX_DESCRIPTORS; x++)
-  {
-    if (DIDD_Table[x].type == IDI_DADAPTER)
-    {  /* DADAPTER found */
-      dadapter = 1;
-      memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
-      req.didd_notify.e.Req = 0;
-      req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
-      req.didd_notify.info.callback = didd_callback;
-      req.didd_notify.info.context = 0;
-      DAdapter.request((ENTITY *)&req);
-      if (req.didd_notify.e.Rc != 0xff)
-			{
-					stop_dbg();
-					return(0);
-			}
-      notify_handle = req.didd_notify.info.handle;
-    }
-    else if (DIDD_Table[x].type == IDI_DIMAINT)
-    {  /* MAINT found */
-      memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
-      dprintf = (DIVA_DI_PRINTF)MAdapter.request;
-      DbgRegister("I4L", DRIVERRELEASE, DBG_DEFAULT);
-    }
-    else if ((DIDD_Table[x].type > 0) &&
-             (DIDD_Table[x].type < 16))
-    {  /* IDI Adapter found */
-      if (DIDD_Table[x].channels) {
-        eicon_addcard(&DIDD_Table[x]);
-      }
-    }
-  }
-
-	if (!dadapter) {
-			stop_dbg();
-	}
-
-  return(dadapter);
-}
-
-static void __exit
-disconnect_didd(void)
-{
-  IDI_SYNC_REQ req;
-
-	stop_dbg();
-
-  req.didd_notify.e.Req = 0;
-  req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
-  req.didd_notify.info.handle = notify_handle;
-  DAdapter.request((ENTITY *)&req);
-}
-
-/*
-** proc entry
-*/
-extern struct proc_dir_entry *proc_net_isdn_eicon;
-static struct proc_dir_entry *i4lidi_proc_entry = NULL;
-
-static int
-i4lidi_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
-  int len = 0;
-  char tmprev[32];
-
-  len += sprintf(page+len, "%s\n", DRIVERNAME);
-  len += sprintf(page+len, "name     : %s\n", DRIVERLNAME);
-  len += sprintf(page+len, "release  : %s\n", DRIVERRELEASE);
-  strcpy(tmprev, eicon_revision);
-  len += sprintf(page+len, "revision : %s/", eicon_getrev(tmprev));
-  strcpy(tmprev, eicon_idi_revision);
-  len += sprintf(page+len, "%s\n", eicon_getrev(tmprev));
-
-  if (off + count >= len)
-    *eof = 1;
-  if (len < off)
-    return 0;
-  *start = page + off;
-  return((count < len-off) ? count : len-off);
-}
-
-static void __init
-create_proc(void)
-{
-  if(!(i4lidi_proc_entry = create_proc_entry(DRIVERLNAME,
-                          S_IFREG | S_IRUGO | S_IWUSR, proc_net_isdn_eicon)))
-  {
-    printk(KERN_WARNING "%s: failed to create proc entry.\n", DRIVERLNAME);
-    return;
-  }
-  i4lidi_proc_entry->read_proc = i4lidi_proc_read;
-  i4lidi_proc_entry->owner = THIS_MODULE;
-}
-
-static void __exit
-remove_proc(void)
-{
-  if(i4lidi_proc_entry)
-      remove_proc_entry(DRIVERLNAME,  proc_net_isdn_eicon);
-}
-
-/*
-** load / unload
-*/
-static int __init
-i4l_idi_init(void)
-{
-  int ret = 0;
-  char tmprev[50];
-
-  status_lock = SPIN_LOCK_UNLOCKED;
-  ll_lock = SPIN_LOCK_UNLOCKED;
-
-  if (strlen(id) < 1)
-    strcpy(id, "diva");
-
-  DebugVar = debug;
-
-  init_MUTEX_LOCKED(&diva_thread_sem);
-  init_MUTEX_LOCKED(&diva_thread_end);
-
-  printk(KERN_INFO "%s\n", DRIVERNAME);
-  printk(KERN_INFO "%s: Rel:%s  Rev:",DRIVERLNAME , DRIVERRELEASE);
-  strcpy(tmprev, eicon_revision);
-  printk("%s/", eicon_getrev(tmprev));
-  strcpy(tmprev, eicon_idi_revision);
-  printk("%s\n", eicon_getrev(tmprev));
-
-  diva_init_thread();
-
-  if(!connect_didd()) {
-    printk(KERN_ERR "%s: failed to connect to DIDD.\n", DRIVERLNAME);
-    stop_diva_thread();
-    ret = -EIO;
-    goto out;
-  }    
-  create_proc();
-
-out:
-  return(ret);
-}
-
-static void __exit
-i4l_idi_exit(void)
-{
-  eicon_card *card, *last, *cc;
-  ulong flags;
-
-  spin_lock_irqsave(&ll_lock, flags);
-  cc = cards;
-  card = cc;
-  cards = NULL;
-  spin_unlock_irqrestore(&ll_lock, flags);
-
-  remove_proc();
-
-  while (card) {
-    unregister_card(card, 1); 
-    card = card->next;
-  }
-
-  stop_diva_thread();
-  disconnect_didd();
-
-  card = cc;
-  while (card) {
-    last = card;
-    card = card->next;
-    eicon_freecard(last);
-  }
-  printk(KERN_INFO "%s: module unloaded.\n", DRIVERLNAME);
-}
-
-module_init(i4l_idi_init);
-module_exit(i4l_idi_exit);
diff -Nru a/drivers/isdn/hardware/eicon/i4lididrv.h b/drivers/isdn/hardware/eicon/i4lididrv.h
--- a/drivers/isdn/hardware/eicon/i4lididrv.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,272 +0,0 @@
-/* $Id: i4lididrv.h,v 1.1.2.2 2002/10/02 14:38:37 armin Exp $
- *
- * ISDN interface module for Eicon active cards.
- * I4L - IDI Interface
- *
- * Copyright 1998-2000  by Armin Schindler (mac@melware.de) 
- * Copyright 1999-2002  Cytronics & Melware (info@melware.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- */
-
-
-#ifndef i4lididrv_h
-#define i4lididrv_h
-
-#include <linux/isdn.h>
-#include <linux/isdnif.h>
-
-#include "platform.h"
-#include "di_defs.h"
-
-#define EICON_IOCTL_GETTYPE   6
-#define EICON_IOCTL_LOADPCI   7 
-#define EICON_IOCTL_GETVER    9 
-#define EICON_IOCTL_GETXLOG  10 
-
-#define EICON_IOCTL_MANIF    90 
-
-#define EICON_IOCTL_FREEIT   97
-#define EICON_IOCTL_TEST     98
-#define EICON_IOCTL_DEBUGVAR 99
-
-/* Constants for describing Card-Type */
-#define EICON_CTYPE_S            0
-#define EICON_CTYPE_SX           1
-#define EICON_CTYPE_SCOM         2
-#define EICON_CTYPE_QUADRO       3
-#define EICON_CTYPE_S2M          4
-#define EICON_CTYPE_MAESTRA      5
-#define EICON_CTYPE_MAESTRAQ     6
-#define EICON_CTYPE_MAESTRAQ_U   7
-#define EICON_CTYPE_MAESTRAP     8
-#define EICON_CTYPE_ISABRI       0x10
-#define EICON_CTYPE_ISAPRI       0x20
-#define EICON_CTYPE_MASK         0x0f
-#define EICON_CTYPE_QUADRO_NR(n) (n<<4)
-
-#define MAX_HEADER_LEN 10
-
-#define MAX_STATUS_BUFFER	150
-
-/* Data for Management interface */
-typedef struct {
-	int count;
-	int pos;
-	int length[50];
-	unsigned char data[700]; 
-} eicon_manifbuf;
-
-#define TRACE_OK                 (1)
-
-#ifdef __KERNEL__
-
-/* Macro for delay via schedule() */
-#define SLEEP(j) {                     \
-  set_current_state(TASK_INTERRUPTIBLE); \
-  schedule_timeout(j);                 \
-}
-
-/* Kernel includes */
-#include <linux/config.h>
-#include <linux/sched.h>
-#include <linux/skbuff.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/ctype.h>
-
-typedef struct {
-  __u16 length __attribute__ ((packed)); /* length of data/parameter field */
-  __u8  P[1];                          /* data/parameter field */
-} eicon_PBUFFER;
-
-typedef struct {
-  __u16 NextReq  __attribute__ ((packed));  /* pointer to next Req Buffer */
-  __u16 NextRc   __attribute__ ((packed));  /* pointer to next Rc Buffer  */
-  __u16 NextInd  __attribute__ ((packed));  /* pointer to next Ind Buffer */
-  __u8 ReqInput  __attribute__ ((packed));  /* number of Req Buffers sent */
-  __u8 ReqOutput  __attribute__ ((packed)); /* number of Req Buffers returned */
-  __u8 ReqReserved  __attribute__ ((packed));/*number of Req Buffers reserved */
-  __u8 Int  __attribute__ ((packed));       /* ISDN-P interrupt           */
-  __u8 XLock  __attribute__ ((packed));     /* Lock field for arbitration */
-  __u8 RcOutput  __attribute__ ((packed));  /* number of Rc buffers received */
-  __u8 IndOutput  __attribute__ ((packed)); /* number of Ind buffers received */
-  __u8 IMask  __attribute__ ((packed));     /* Interrupt Mask Flag        */
-  __u8 Reserved1[2]  __attribute__ ((packed)); /* reserved field, do not use */
-  __u8 ReadyInt  __attribute__ ((packed));  /* request field for ready int */
-  __u8 Reserved2[12]  __attribute__ ((packed)); /* reserved field, do not use */
-  __u8 InterfaceType  __attribute__ ((packed)); /* interface type 1=16K    */
-  __u16 Signature  __attribute__ ((packed));    /* ISDN-P initialized ind  */
-  __u8 B[1];                            /* buffer space for Req,Ind and Rc */
-} eicon_pr_ram;
-
-typedef struct {
-  __u8                  Req;            /* pending request          */
-  __u8                  Rc;             /* return code received     */
-  __u8                  Ind;            /* indication received      */
-  __u8                  ReqCh;          /* channel of current Req   */
-  __u8                  RcCh;           /* channel of current Rc    */
-  __u8                  IndCh;          /* channel of current Ind   */
-  __u8                  D3Id;           /* ID used by this entity   */
-  __u8                  B2Id;           /* ID used by this entity   */
-  __u8                  GlobalId;       /* reserved field           */
-  __u8                  XNum;           /* number of X-buffers      */
-  __u8                  RNum;           /* number of R-buffers      */
-  struct sk_buff_head   X;              /* X-buffer queue           */
-  struct sk_buff_head   R;              /* R-buffer queue           */
-  __u8                  RNR;            /* receive not ready flag   */
-  __u8                  complete;       /* receive complete status  */
-  __u8                  busy;           /* busy flag                */
-  __u16                 ref;            /* saved reference          */
-} entity;
-
-#define FAX_MAX_SCANLINE 2500 
-
-typedef struct {
-	__u8		PrevObject;
-	__u8		NextObject;
-	__u8		abLine[FAX_MAX_SCANLINE];
-	__u8		abFrame[FAX_MAX_SCANLINE];
-	unsigned int	LineLen;
-	unsigned int	LineDataLen;
-	__u32		LineData;
-	unsigned int	NullBytesPos;
-	__u8		NullByteExist;
-	int		PageCount;
-	__u8		Dle;
-	__u8		Eop;
-} eicon_ch_fax_buf;
-
-typedef struct {
-	int	       No;		 /* Channel Number	        */
-	unsigned short fsm_state;        /* Current D-Channel state     */
-	unsigned short statectrl;	 /* State controling bits	*/
-	unsigned short eazmask;          /* EAZ-Mask for this Channel   */
-	int		queued;          /* User-Data Bytes in TX queue */
-	int		pqueued;         /* User-Data Packets in TX queue */
-	int		waitq;           /* User-Data Bytes in wait queue */
-	int		waitpq;          /* User-Data Bytes in packet queue */
-	struct sk_buff *tskb1;           /* temp skb 1			*/
-	struct sk_buff *tskb2;           /* temp skb 2			*/
-	unsigned char  l2prot;           /* Layer 2 protocol            */
-	unsigned char  l3prot;           /* Layer 3 protocol            */
-#ifdef CONFIG_ISDN_TTY_FAX
-	T30_s		*fax;		 /* pointer to fax data in LL	*/
-	eicon_ch_fax_buf fax2;		 /* fax related struct		*/
-#endif
-	entity		e;		 /* Native Entity		*/
-	ENTITY		de;		 /* Divas D Entity 		*/
-	ENTITY		be;		 /* Divas B Entity 		*/
-	char		cpn[32];	 /* remember cpn		*/
-	char		oad[32];	 /* remember oad		*/
-	char		dsa[32];	 /* remember dsa		*/
-	char		osa[32];	 /* remember osa		*/
-	unsigned char   cause[2];	 /* Last Cause			*/
-	unsigned char	si1;
-	unsigned char	si2;
-	unsigned char	plan;
-	unsigned char	screen;
-        unsigned char   a_para[8];       /* Additional parameter        */
-} eicon_chan;
-
-typedef struct {
-	eicon_chan *ptr;
-} eicon_chan_ptr;
-
-
-#define EICON_FLAGS_RUNNING  1 /* Cards driver activated */
-#define EICON_FLAGS_LOADED   8 /* Firmware loaded        */
-
-/* D-Channel states */
-#define EICON_STATE_NULL     0
-#define EICON_STATE_ICALL    1
-#define EICON_STATE_OCALL    2
-#define EICON_STATE_IWAIT    3
-#define EICON_STATE_OWAIT    4
-#define EICON_STATE_IBWAIT   5
-#define EICON_STATE_OBWAIT   6
-#define EICON_STATE_BWAIT    7
-#define EICON_STATE_BHWAIT   8
-#define EICON_STATE_BHWAIT2  9
-#define EICON_STATE_DHWAIT  10
-#define EICON_STATE_DHWAIT2 11
-#define EICON_STATE_BSETUP  12
-#define EICON_STATE_ACTIVE  13
-#define EICON_STATE_ICALLW  14
-#define EICON_STATE_LISTEN  15
-#define EICON_STATE_WMCONN  16
-
-#define EICON_MAX_QUEUE  2138
-
-typedef struct {
-	__u8 ret;
-	__u8 id;
-	__u8 ch;
-} eicon_ack;
-
-typedef struct {
-	__u8 code;
-	__u8 id;
-	__u8 ch;
-} eicon_req;
-
-typedef struct {
-	__u8 ret;
-	__u8 id;
-	__u8 ch;
-	__u8 more;
-} eicon_indhdr;
-
-/*
- * Per card driver data
- */
-typedef struct eicon_card {
-	DESCRIPTOR d;			 /* IDI Descriptor		     */
-        u_char ptype;                    /* Protocol type (1TR6 or Euro)     */
-        u_char type;                     /* Cardtype (EICON_CTYPE_...)       */
-	struct eicon_card *qnext;  	 /* Pointer to next quadro adapter   */
-        int Feature;                     /* Protocol Feature Value           */
-        struct eicon_card *next;	 /* Pointer to next device struct    */
-        int myid;                        /* Driver-Nr. assigned by linklevel */
-        unsigned long flags;             /* Statusflags                      */
-	struct sk_buff_head rcvq;        /* Receive-Message queue            */
-	struct sk_buff_head sndq;        /* Send-Message queue               */
-	struct sk_buff_head rackq;       /* Req-Ack-Message queue            */
-	struct sk_buff_head sackq;       /* Data-Ack-Message queue           */
-	struct sk_buff_head statq;       /* Status-Message queue             */
-	int statq_entries;
-	eicon_chan*	IdTable[256];	 /* Table to find entity   */
-	__u16  ref_in;
-	__u16  ref_out;
-	int    nchannels;                /* Number of B-Channels             */
-	int    ReadyInt;		 /* Ready Interrupt		     */
-	eicon_chan *bch;                 /* B-Channel status/control         */
-	DBUFFER *dbuf;			 /* Dbuffer for Diva Server	     */
-	BUFFERS *sbuf;			 /* Buffer for Diva Server	     */
-	char *sbufp;			 /* Data Buffer for Diva Server	     */
-        isdn_if interface;               /* Interface to upper layer         */
-        char regname[35];                /* Drivers card name 		     */
-	spinlock_t lock;		 /* spin lock per card		     */
-        struct tq_struct tq;             /* task queue for thread            */
-} eicon_card;
-
-#include "i4l_idi.h"
-
-extern eicon_card *cards;
-extern char *eicon_ctype_name[];
-
-extern ulong DebugVar;
-extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
-extern void eicon_putstatus(eicon_card * card, char * buf);
-
-extern void eicon_tx_request(struct eicon_card *);
-
-extern spinlock_t eicon_lock;
-
-#endif  /* __KERNEL__ */
-
-#endif	/* i4lididrv_h */
diff -Nru a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c
--- a/drivers/isdn/hardware/eicon/idifunc.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/isdn/hardware/eicon/idifunc.c	Sat Apr  3 19:38:56 2004
@@ -1,4 +1,4 @@
-/* $Id: idifunc.c,v 1.13 2003/08/25 14:49:53 schindler Exp $
+/* $Id: idifunc.c,v 1.14 2004/03/21 18:13:43 armin Exp $
  *
  * Driver for Eicon DIVA Server ISDN cards.
  * User Mode IDI Interface 
@@ -49,76 +49,37 @@
 }
 
 typedef struct _udiva_card {
-	struct _udiva_card *next;
+	struct list_head list;
 	int Id;
 	DESCRIPTOR d;
 } udiva_card;
 
-static udiva_card *cards;
+static LIST_HEAD(cards);
 static diva_os_spin_lock_t ll_lock;
 
 /*
- * add card to list
- */
-static void add_card_to_list(udiva_card * c)
-{
-	diva_os_spin_lock_magic_t old_irql;
-
-	diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card");
-	c->next = cards;
-	cards = c;
-	diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card");
-}
-
-/*
  * find card in list
  */
 static udiva_card *find_card_in_list(DESCRIPTOR * d)
 {
 	udiva_card *card;
+	struct list_head *tmp;
 	diva_os_spin_lock_magic_t old_irql;
 
 	diva_os_enter_spin_lock(&ll_lock, &old_irql, "find card");
-	card = cards;
-	while (card) {
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, udiva_card, list);
 		if (card->d.request == d->request) {
 			diva_os_leave_spin_lock(&ll_lock, &old_irql,
 						"find card");
 			return (card);
 		}
-		card = card->next;
 	}
 	diva_os_leave_spin_lock(&ll_lock, &old_irql, "find card");
 	return ((udiva_card *) NULL);
 }
 
 /*
- * remove card from list
- */
-static void remove_card_from_list(udiva_card * c)
-{
-	udiva_card *list = NULL, *last;
-	diva_os_spin_lock_magic_t old_irql;
-
-	diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card");
-	list = cards;
-	last = list;
-	while (list) {
-		if (list == c) {
-			if (cards == c) {
-				cards = c->next;
-			} else {
-				last->next = c->next;
-			}
-			break;
-		}
-		last = list;
-		list = list->next;
-	}
-	diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card");
-}
-
-/*
  * new card
  */
 static void um_new_card(DESCRIPTOR * d)
@@ -126,6 +87,7 @@
 	int adapter_nr = 0;
 	udiva_card *card = NULL;
 	IDI_SYNC_REQ sync_req;
+	diva_os_spin_lock_magic_t old_irql;
 
 	if (!(card = diva_os_malloc(0, sizeof(udiva_card)))) {
 		DBG_ERR(("cannot get buffer for card"));
@@ -140,7 +102,9 @@
 	    sync_req.xdi_logical_adapter_number.info.logical_adapter_number;
 	card->Id = adapter_nr;
 	if (!(diva_user_mode_idi_create_adapter(d, adapter_nr))) {
-		add_card_to_list(card);
+		diva_os_enter_spin_lock(&ll_lock, &old_irql, "add card");
+		list_add_tail(&card->list, &cards);
+		diva_os_leave_spin_lock(&ll_lock, &old_irql, "add card");
 	} else {
 		DBG_ERR(("could not create user mode idi card %d",
 			 adapter_nr));
@@ -152,6 +116,7 @@
  */
 static void um_remove_card(DESCRIPTOR * d)
 {
+	diva_os_spin_lock_magic_t old_irql;
 	udiva_card *card = NULL;
 
 	if (!(card = find_card_in_list(d))) {
@@ -159,7 +124,9 @@
 		return;
 	}
 	diva_user_mode_idi_remove_adapter(card->Id);
-	remove_card_from_list(card);
+	diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove card");
+	list_del(&card->list);
+	diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove card");
 	DBG_LOG(("idi proc entry removed for card %d", card->Id));
 	diva_os_free(0, card);
 }
@@ -169,20 +136,20 @@
  */
 static void DIVA_EXIT_FUNCTION remove_all_idi_proc(void)
 {
-	udiva_card *card, *last;
+	udiva_card *card;
+	struct list_head *tmp;
 	diva_os_spin_lock_magic_t old_irql;
 
+rescan:
 	diva_os_enter_spin_lock(&ll_lock, &old_irql, "remove all");
-	card = cards;
-	cards = NULL;
+	list_for_each(tmp, &cards) {
+		card = list_entry(tmp, udiva_card, list);
 	diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all");
-
-	while (card) {
 		diva_user_mode_idi_remove_adapter(card->Id);
-		last = card;
-		card = card->next;
-		diva_os_free(0, last);
+		diva_os_free(0, card);
+		goto rescan;
 	}
+	diva_os_leave_spin_lock(&ll_lock, &old_irql, "remove all");
 }
 
 /*
diff -Nru a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
--- a/drivers/isdn/hardware/eicon/message.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/isdn/hardware/eicon/message.c	Sat Apr  3 19:38:44 2004
@@ -14821,7 +14821,7 @@
   for(i=0;i<MAX_CIP_TYPES;i++)
   {
     info_mask_group[i] = 0;
-    cip_mask_group [i] = 0;;
+    cip_mask_group [i] = 0;
   }
   for(i=0;i<MAX_APPL;i++)
   {
diff -Nru a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c
--- a/drivers/isdn/hardware/eicon/os_4bri.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/isdn/hardware/eicon/os_4bri.c	Sat Apr  3 19:38:43 2004
@@ -1,9 +1,8 @@
-/* $Id: os_4bri.c,v 1.25 2003/06/21 17:08:44 schindler Exp $ */
+/* $Id: os_4bri.c,v 1.28 2004/03/21 17:26:01 armin Exp $ */
 
 #include "platform.h"
 #include "debuglib.h"
 #include "cardtype.h"
-#include "dlist.h"
 #include "pc.h"
 #include "pr_pc.h"
 #include "di_defs.h"
diff -Nru a/drivers/isdn/hardware/eicon/os_bri.c b/drivers/isdn/hardware/eicon/os_bri.c
--- a/drivers/isdn/hardware/eicon/os_bri.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/isdn/hardware/eicon/os_bri.c	Sat Apr  3 19:38:41 2004
@@ -1,9 +1,8 @@
-/* $Id: os_bri.c,v 1.18 2003/06/21 17:10:29 schindler Exp $ */
+/* $Id: os_bri.c,v 1.21 2004/03/21 17:26:01 armin Exp $ */
 
 #include "platform.h"
 #include "debuglib.h"
 #include "cardtype.h"
-#include "dlist.h"
 #include "pc.h"
 #include "pr_pc.h"
 #include "di_defs.h"
diff -Nru a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c
--- a/drivers/isdn/hardware/eicon/os_pri.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/isdn/hardware/eicon/os_pri.c	Sat Apr  3 19:38:43 2004
@@ -1,9 +1,8 @@
-/* $Id: os_pri.c,v 1.29 2003/08/25 13:41:27 schindler Exp $ */
+/* $Id: os_pri.c,v 1.32 2004/03/21 17:26:01 armin Exp $ */
 
 #include "platform.h"
 #include "debuglib.h"
 #include "cardtype.h"
-#include "dlist.h"
 #include "pc.h"
 #include "pr_pc.h"
 #include "di_defs.h"
diff -Nru a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
--- a/drivers/isdn/hardware/eicon/platform.h	Sat Apr  3 19:38:54 2004
+++ b/drivers/isdn/hardware/eicon/platform.h	Sat Apr  3 19:38:54 2004
@@ -1,4 +1,4 @@
-/* $Id: platform.h,v 1.35 2003/12/05 18:45:05 armin Exp $
+/* $Id: platform.h,v 1.37 2004/03/20 17:44:29 armin Exp $
  *
  * platform.h
  * 
@@ -29,6 +29,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 #include <linux/delay.h>
+#include <linux/list.h>
 #include <asm/types.h>
 #include <asm/io.h>
 
@@ -332,7 +333,6 @@
 */
 #define NO_CORNETN
 #define IMPLEMENT_DTMF 1
-#define IMPLEMENT_LINE_INTERCONNECT2 1
 #define IMPLEMENT_ECHO_CANCELLER 1
 #define IMPLEMENT_RTP 1
 #define IMPLEMENT_T38 1
@@ -346,7 +346,6 @@
 #define IMPLEMENT_FAX_NONSTANDARD 1
 #define VSWITCH_SUPPORT 1
 
-#define IMPLEMENT_LINE_INTERCONNECT  0
 #define IMPLEMENT_MARKED_OK_AFTER_FC 1
 
 #define DIVA_IDI_RX_DMA 1
diff -Nru a/drivers/isdn/hardware/eicon/um_idi.c b/drivers/isdn/hardware/eicon/um_idi.c
--- a/drivers/isdn/hardware/eicon/um_idi.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/isdn/hardware/eicon/um_idi.c	Sat Apr  3 19:38:45 2004
@@ -1,9 +1,8 @@
-/* $Id: um_idi.c,v 1.12 2004/01/12 18:00:09 armin Exp $ */
+/* $Id: um_idi.c,v 1.14 2004/03/21 17:54:37 armin Exp $ */
 
 #include "platform.h"
 #include "di_defs.h"
 #include "pc.h"
-#include "dlist.h"
 #include "dqueue.h"
 #include "adapter.h"
 #include "entity.h"
@@ -22,7 +21,7 @@
 /* --------------------------------------------------------------------------
 		LOCALS
    -------------------------------------------------------------------------- */
-static diva_entity_queue_t adapter_q;
+static LIST_HEAD(adapter_q);
 static diva_os_spin_lock_t adapter_lock;
 
 static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr);
@@ -37,17 +36,11 @@
 static int process_idi_ind(divas_um_idi_entity_t * e, byte ind);
 static int write_return_code(divas_um_idi_entity_t * e, byte rc);
 
-/*
- * include queue functions
- */
-#include "dlist.c"
-
 /* --------------------------------------------------------------------------
 		MAIN
    -------------------------------------------------------------------------- */
 int diva_user_mode_idi_init(void)
 {
-	diva_q_init(&adapter_q);
 	diva_os_initialize_spin_lock(&adapter_lock, "adapter");
 	return (0);
 }
@@ -89,18 +82,18 @@
    -------------------------------------------------------------------------- */
 void diva_user_mode_idi_remove_adapter(int adapter_nr)
 {
-	diva_um_idi_adapter_t *a =
-	    (diva_um_idi_adapter_t *) diva_q_get_head(&adapter_q);
+	struct list_head *tmp;
+	diva_um_idi_adapter_t *a;
 
-	while (a) {
+	list_for_each(tmp, &adapter_q) {
+		a = list_entry(tmp, diva_um_idi_adapter_t, link);
 		if (a->adapter_nr == adapter_nr) {
-			diva_q_remove(&adapter_q, &a->link);
+			list_del(tmp);
 			cleanup_adapter(a);
 			DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr));
 			diva_os_free(0, a);
 			break;
 		}
-		a = (diva_um_idi_adapter_t *) diva_q_get_next(&a->link);
 	}
 }
 
@@ -109,15 +102,15 @@
    -------------------------------------------------------------------------- */
 void diva_user_mode_idi_finit(void)
 {
-	diva_um_idi_adapter_t *a =
-	    (diva_um_idi_adapter_t *) diva_q_get_head(&adapter_q);
+	struct list_head *tmp, *safe;
+	diva_um_idi_adapter_t *a;
 
-	while (a) {
-		diva_q_remove(&adapter_q, &a->link);
+	list_for_each_safe(tmp, safe, &adapter_q) {
+		a = list_entry(tmp, diva_um_idi_adapter_t, link);
+		list_del(tmp);
 		cleanup_adapter(a);
 		DBG_LOG(("DIDD: del adapter(%d)", a->adapter_nr));
 		diva_os_free(0, a);
-		a = (diva_um_idi_adapter_t *) diva_q_get_head(&adapter_q);
 	}
 	diva_os_destroy_spin_lock(&adapter_lock, "adapter");
 }
@@ -137,6 +130,7 @@
 		return (-1);
 	}
 	memset(a, 0x00, sizeof(*a));
+	INIT_LIST_HEAD(&a->entity_q);
 
 	a->d = *d;
 	a->adapter_nr = adapter_nr;
@@ -145,46 +139,27 @@
 		 adapter_nr, a->d.type, a->d.features, a->d.channels));
 
 	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "create_adapter");
-	diva_q_add_tail(&adapter_q, &a->link);
+	list_add_tail(&a->link, &adapter_q);
 	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_adapter");
 	return (0);
 }
 
-static int cmp_adapter_nr(const void *what, const diva_entity_link_t * p)
-{
-	diva_um_idi_adapter_t *a = (diva_um_idi_adapter_t *) p;
-	dword nr = (dword) (unsigned long) what;
-
-	DBG_TRC(("find_adapter: (%d)-(%d)", nr, a->adapter_nr));
-
-	return (nr != a->adapter_nr);
-}
-
 /* ------------------------------------------------------------------------
 			Find adapter by Adapter number
    ------------------------------------------------------------------------ */
 static diva_um_idi_adapter_t *diva_um_idi_find_adapter(dword nr)
 {
-	return (diva_um_idi_adapter_t *) diva_q_find(&adapter_q,
-						     (void *) (unsigned
-							       long) nr,
-						     cmp_adapter_nr);
-}
+	diva_um_idi_adapter_t *a = NULL;
+	struct list_head *tmp;
 
-/* ------------------------------------------------------------------------
-		Return number of adapters in system
-   ------------------------------------------------------------------------ */
-int diva_um_idi_nr_of_adapters(void)
-{
-	int i = 0;
-	const diva_entity_queue_t * q = &adapter_q;
-	const diva_entity_link_t *diva_current = q->head;
-
-	while (diva_current) {
-		i++;
-		diva_current = diva_current->next;
+	list_for_each(tmp, &adapter_q) {
+		a = list_entry(tmp, diva_um_idi_adapter_t, link);
+		DBG_TRC(("find_adapter: (%d)-(%d)", nr, a->adapter_nr));
+		if (a->adapter_nr == (int)nr)
+			break;
+		a = NULL;
 	}
-	return(i);
+	return(a);
 }
 
 /* ------------------------------------------------------------------------
@@ -193,17 +168,17 @@
    ------------------------------------------------------------------------ */
 static void cleanup_adapter(diva_um_idi_adapter_t * a)
 {
-	divas_um_idi_entity_t *e =
-	    (divas_um_idi_entity_t *) diva_q_get_head(&a->entity_q);
+	struct list_head *tmp, *safe;
+	divas_um_idi_entity_t *e;
 
-	while (e) {
-		diva_q_remove(&a->entity_q, &e->link);
+	list_for_each_safe(tmp, safe, &a->entity_q) {
+		e = list_entry(tmp, divas_um_idi_entity_t, link);
+		list_del(tmp);
 		cleanup_entity(e);
 		if (e->os_context) {
 			diva_os_wakeup_read(e->os_context);
 			diva_os_wakeup_close(e->os_context);
 		}
-		e = (divas_um_idi_entity_t *) diva_q_get_head(&a->entity_q);
 	}
 	memset(&a->d, 0x00, sizeof(DESCRIPTOR));
 }
@@ -281,7 +256,7 @@
 		e->os_ref = file;	/* link to os handle */
 		e->adapter = a;	/* link to adapter   */
 
-		diva_q_add_tail(&a->entity_q, &e->link);	/* link from adapter */
+		list_add_tail(&e->link, &a->entity_q);	/* link from adapter */
 
 		diva_os_leave_spin_lock(&adapter_lock, &old_irql, "create_entity");
 
@@ -305,7 +280,7 @@
 
 	diva_os_enter_spin_lock(&adapter_lock, &old_irql, "delete_entity");
 	if ((a = e->adapter)) {
-		diva_q_remove(&a->entity_q, &e->link);
+		list_del(&e->link);
 	}
 	diva_os_leave_spin_lock(&adapter_lock, &old_irql, "delete_entity");
 
diff -Nru a/drivers/isdn/hardware/eicon/um_idi.h b/drivers/isdn/hardware/eicon/um_idi.h
--- a/drivers/isdn/hardware/eicon/um_idi.h	Sat Apr  3 19:38:57 2004
+++ b/drivers/isdn/hardware/eicon/um_idi.h	Sat Apr  3 19:38:57 2004
@@ -1,4 +1,4 @@
-/* $Id: um_idi.h,v 1.1.2.2 2002/10/02 14:38:38 armin Exp $ */
+/* $Id: um_idi.h,v 1.6 2004/03/21 17:26:01 armin Exp $ */
 
 #ifndef __DIVA_USER_MODE_IDI_CORE_H__
 #define __DIVA_USER_MODE_IDI_CORE_H__
@@ -9,7 +9,6 @@
   */
 int diva_user_mode_idi_init(void);
 void diva_user_mode_idi_finit(void);
-int diva_um_idi_nr_of_adapters(void);
 void *divas_um_idi_create_entity(dword adapter_nr, void *file);
 int divas_um_idi_delete_entity(int adapter_nr, void *entity);
 
diff -Nru a/drivers/isdn/hardware/eicon/xdi_adapter.h b/drivers/isdn/hardware/eicon/xdi_adapter.h
--- a/drivers/isdn/hardware/eicon/xdi_adapter.h	Sat Apr  3 19:38:44 2004
+++ b/drivers/isdn/hardware/eicon/xdi_adapter.h	Sat Apr  3 19:38:44 2004
@@ -1,4 +1,4 @@
-/* $Id: xdi_adapter.h,v 1.6 2003/12/05 18:45:05 armin Exp $ */
+/* $Id: xdi_adapter.h,v 1.7 2004/03/21 17:26:01 armin Exp $ */
 
 #ifndef __DIVA_OS_XDI_ADAPTER_H__
 #define __DIVA_OS_XDI_ADAPTER_H__
@@ -47,7 +47,7 @@
 } diva_os_idi_adapter_interface_t;
 
 typedef struct _diva_os_xdi_adapter {
-	diva_entity_link_t link;
+	struct list_head link;
 	int CardIndex;
 	int CardOrdinal;
 	int controller;		/* number of this controller */
diff -Nru a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
--- a/drivers/isdn/hisax/hfc_usb.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/isdn/hisax/hfc_usb.c	Sat Apr  3 19:38:42 2004
@@ -1349,9 +1349,11 @@
 {
 	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 @@
 
 #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 @@
 		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 @@
 
 #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 @@
 					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 @@
 				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 @@
 
 			// 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 -Nru a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c	Sat Apr  3 19:38:54 2004
@@ -762,7 +762,7 @@
 	adapter->isac.priv = adapter;
 	switch (adapter->type) {
 	case AVM_FRITZ_PCIV2:
-		adapter->isac.read_isac       = &fcpci2_read_isac;;
+		adapter->isac.read_isac       = &fcpci2_read_isac;
 		adapter->isac.write_isac      = &fcpci2_write_isac;
 		adapter->isac.read_isac_fifo  = &fcpci2_read_isac_fifo;
 		adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo;
@@ -771,7 +771,7 @@
 		adapter->write_ctrl           = &fcpci2_write_ctrl;
 		break;
 	case AVM_FRITZ_PCI:
-		adapter->isac.read_isac       = &fcpci_read_isac;;
+		adapter->isac.read_isac       = &fcpci_read_isac;
 		adapter->isac.write_isac      = &fcpci_write_isac;
 		adapter->isac.read_isac_fifo  = &fcpci_read_isac_fifo;
 		adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
@@ -780,7 +780,7 @@
 		adapter->write_ctrl           = &fcpci_write_ctrl;
 		break;
 	case AVM_FRITZ_PNP:
-		adapter->isac.read_isac       = &fcpci_read_isac;;
+		adapter->isac.read_isac       = &fcpci_read_isac;
 		adapter->isac.write_isac      = &fcpci_write_isac;
 		adapter->isac.read_isac_fifo  = &fcpci_read_isac_fifo;
 		adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo;
diff -Nru a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
--- a/drivers/isdn/hisax/niccy.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/isdn/hisax/niccy.c	Sat Apr  3 19:38:42 2004
@@ -271,7 +271,7 @@
 			}
 			card->para[1] = pnp_port_start(pnp_d, 0);
 			card->para[2] = pnp_port_start(pnp_d, 1);
-			card->para[0] = pnp_irq(pnp_d, 0);;
+			card->para[0] = pnp_irq(pnp_d, 0);
 			if (!card->para[0] || !card->para[1] || !card->para[2]) {
 				printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
 					card->para[0], card->para[1], card->para[2]);
diff -Nru a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
--- a/drivers/isdn/hisax/nj_s.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/isdn/hisax/nj_s.c	Sat Apr  3 19:38:42 2004
@@ -80,7 +80,7 @@
 			printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n",
 				cs->hw.njet.last_is0, s0val);
 			spin_unlock_irqrestore(&cs->lock, flags);
-			return IRQ_HANDLED;;
+			return IRQ_HANDLED;
 		}
 		cs->hw.njet.irqstat0 = s0val;
 		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != 
diff -Nru a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
--- a/drivers/macintosh/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/drivers/macintosh/Kconfig	Sat Apr  3 19:38:43 2004
@@ -1,5 +1,6 @@
 
 menu "Macintosh device drivers"
+	depends on PPC || MAC
 
 config ADB
 	bool "Apple Desktop Bus (ADB) support"
@@ -174,8 +175,8 @@
 	  This driver provides some thermostat and fan control for the desktop
 	  G4 "Windtunnel"
 
-config THERM_ADT7467
-	tristate "Support for thermal mgmnt on laptops with ADT 7467 chipset"
+config THERM_ADT746X
+	tristate "Support for thermal mgmnt on laptops with ADT 746x chipset"
 	depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
 	help
 	  This driver provides some thermostat and fan control for the
diff -Nru a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
--- a/drivers/macintosh/Makefile	Sat Apr  3 19:38:55 2004
+++ b/drivers/macintosh/Makefile	Sat Apr  3 19:38:55 2004
@@ -25,4 +25,4 @@
 
 obj-$(CONFIG_THERM_PM72)	+= therm_pm72.o
 obj-$(CONFIG_THERM_WINDTUNNEL)	+= therm_windtunnel.o
-obj-$(CONFIG_THERM_ADT7467)	+= therm_adt7467.o
+obj-$(CONFIG_THERM_ADT746X)	+= therm_adt746x.o
diff -Nru a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
--- a/drivers/macintosh/adbhid.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/macintosh/adbhid.c	Sat Apr  3 19:38:57 2004
@@ -107,7 +107,6 @@
 static void adbhid_probe(void);
 
 static void adbhid_input_keycode(int, int, int, struct pt_regs *);
-static void leds_done(struct adb_request *);
 
 static void init_trackpad(int id);
 static void init_trackball(int id);
@@ -446,24 +445,54 @@
 
 static struct adb_request led_request;
 static int leds_pending[16];
+static int leds_req_pending;
 static int pending_devs[16];
 static int pending_led_start=0;
 static int pending_led_end=0;
+static spinlock_t leds_lock  = SPIN_LOCK_UNLOCKED;
+
+static void leds_done(struct adb_request *req)
+{
+	int leds, device;
+	unsigned long flags;
+
+	spin_lock_irqsave(&leds_lock, flags);
+
+	if (pending_led_start != pending_led_end) {
+		device = pending_devs[pending_led_start];
+		leds = leds_pending[device] & 0xff;
+		leds_pending[device] = 0;
+		pending_led_start++;
+		pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
+	} else
+		leds_req_pending = 0;
+
+	spin_unlock_irqrestore(&leds_lock, flags);
+	if (leds_req_pending)
+		adb_request(&led_request, leds_done, 0, 3,
+			    ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds);
+}
 
 static void real_leds(unsigned char leds, int device)
 {
-    if (led_request.complete) {
-	adb_request(&led_request, leds_done, 0, 3,
-		    ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
-		    ~leds);
-    } else {
-	if (!(leds_pending[device] & 0x100)) {
-	    pending_devs[pending_led_end] = device;
-	    pending_led_end++;
-	    pending_led_end = (pending_led_end < 16) ? pending_led_end : 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&leds_lock, flags);
+	if (!leds_req_pending) {
+		leds_req_pending = 1;
+		spin_unlock_irqrestore(&leds_lock, flags);	       
+		adb_request(&led_request, leds_done, 0, 3,
+			    ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds);
+		return;
+	} else {
+		if (!(leds_pending[device] & 0x100)) {
+			pending_devs[pending_led_end] = device;
+			pending_led_end++;
+			pending_led_end = (pending_led_end < 16) ? pending_led_end : 0;
+		}
+		leds_pending[device] = leds | 0x100;
 	}
-	leds_pending[device] = leds | 0x100;
-    }
+	spin_unlock_irqrestore(&leds_lock, flags);	       
 }
 
 /*
@@ -487,21 +516,6 @@
 	return -1;
 }
 
-static void leds_done(struct adb_request *req)
-{
-    int leds,device;
-
-    if (pending_led_start != pending_led_end) {
-	device = pending_devs[pending_led_start];
-	leds = leds_pending[device] & 0xff;
-	leds_pending[device] = 0;
-	pending_led_start++;
-	pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
-	real_leds(leds,device);
-    }
-
-}
-
 static int
 adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
 {
@@ -518,7 +532,7 @@
 		}
 
 		/* Stop pending led requests */
-		while(!led_request.complete)
+		while(leds_req_pending)
 			adb_poll();
 		break;
 
diff -Nru a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
--- a/drivers/macintosh/mediabay.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/macintosh/mediabay.c	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/drivers/macintosh/therm_adt7467.c b/drivers/macintosh/therm_adt7467.c
--- a/drivers/macintosh/therm_adt7467.c	Sat Apr  3 19:38:54 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,562 +0,0 @@
-/*
- * Device driver for the i2c thermostat found on the iBook G4, Albook G4
- *
- * Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt
- *
- * Documentation from
- * http://www.analog.com/UploadedFiles/Data_Sheets/115254175ADT7467_pra.pdf
- * http://www.analog.com/UploadedFiles/Data_Sheets/3686221171167ADT7460_b.pdf
- *
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/wait.h>
-#include <asm/prom.h>
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sections.h>
-#include <asm/of_device.h>
-
-#undef DEBUG
-
-#define CONFIG_REG   0x40
-#define MANUAL_MASK  0xe0
-#define AUTO_MASK    0x20
-
-static u8 TEMP_REG[3]    = {0x26, 0x25, 0x27}; /* local, cpu, gpu */
-static u8 LIMIT_REG[3]   = {0x6b, 0x6a, 0x6c}; /* local, cpu, gpu */
-static u8 MANUAL_MODE[2] = {0x5c, 0x5d};       
-static u8 REM_CONTROL[2] = {0x00, 0x40};
-static u8 FAN_SPEED[2]   = {0x28, 0x2a};
-static u8 FAN_SPD_SET[2] = {0x30, 0x31};
-
-static u8 default_limits_local[3] = {70, 50, 70};    /* local, cpu, gpu */
-static u8 default_limits_chip[3] = {80, 65, 80};    /* local, cpu, gpu */
-
-static int limit_adjust = 0;
-static int fan_speed = -1;
-
-MODULE_AUTHOR("Colin Leroy <colin@colino.net>");
-MODULE_DESCRIPTION("Driver for ADT7467 thermostat in iBook G4");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM(limit_adjust,"i");
-MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50°C cpu, 70°C gpu) by N °C.");
-MODULE_PARM(fan_speed,"i");
-MODULE_PARM_DESC(fan_speed,"Specify fan speed (0-255) when lim < temp < lim+8 (default 128)");
-
-struct thermostat {
-	struct i2c_client	clt;
-	u8			cached_temp[3];
-	u8			initial_limits[3];
-	u8			limits[3];
-	int			last_speed[2];
-	int			overriding[2];
-};
-
-static enum {ADT7460, ADT7467} therm_type;
-static int therm_bus, therm_address;
-static struct of_device * of_dev;
-static struct thermostat* thermostat;
-static pid_t monitor_thread_id;
-static int monitor_running;
-static struct completion monitor_task_compl;
-
-static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno);
-static void write_both_fan_speed(struct thermostat *th, int speed);
-static void write_fan_speed(struct thermostat *th, int speed, int fan);
-
-static int
-write_reg(struct thermostat* th, int reg, u8 data)
-{
-	u8 tmp[2];
-	int rc;
-	
-	tmp[0] = reg;
-	tmp[1] = data;
-	rc = i2c_master_send(&th->clt, (const char *)tmp, 2);
-	if (rc < 0)
-		return rc;
-	if (rc != 2)
-		return -ENODEV;
-	return 0;
-}
-
-static int
-read_reg(struct thermostat* th, int reg)
-{
-	u8 reg_addr, data;
-	int rc;
-
-	reg_addr = (u8)reg;
-	rc = i2c_master_send(&th->clt, &reg_addr, 1);
-	if (rc < 0)
-		return rc;
-	if (rc != 1)
-		return -ENODEV;
-	rc = i2c_master_recv(&th->clt, (char *)&data, 1);
-	if (rc < 0)
-		return rc;
-	return data;
-}
-
-static int
-attach_thermostat(struct i2c_adapter *adapter)
-{
-	unsigned long bus_no;
-
-	if (strncmp(adapter->name, "uni-n", 5))
-		return -ENODEV;
-	bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
-	if (bus_no != therm_bus)
-		return -ENODEV;
-	return attach_one_thermostat(adapter, therm_address, bus_no);
-}
-
-static int
-detach_thermostat(struct i2c_adapter *adapter)
-{
-	struct thermostat* th;
-	int i;
-	
-	if (thermostat == NULL)
-		return 0;
-
-	th = thermostat;
-
-	if (monitor_running) {
-		monitor_running = 0;
-		wait_for_completion(&monitor_task_compl);
-	}
-		
-	printk(KERN_INFO "adt746x: Putting max temperatures back from %d, %d, %d,"
-		" to %d, %d, %d, (°C)\n", 
-		th->limits[0], th->limits[1], th->limits[2],
-		th->initial_limits[0], th->initial_limits[1], th->initial_limits[2]);
-	
-	for (i = 0; i < 3; i++)
-		write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
-
-	write_both_fan_speed(th, -1);
-
-	i2c_detach_client(&th->clt);
-
-	thermostat = NULL;
-
-	kfree(th);
-
-	return 0;
-}
-
-static struct i2c_driver thermostat_driver = {  
-	.name		="Apple Thermostat ADT7467",
-	.id		=0xDEAD7467,
-	.flags		=I2C_DF_NOTIFY,
-	.attach_adapter	=&attach_thermostat,
-	.detach_adapter	=&detach_thermostat,
-};
-
-static int read_fan_speed(struct thermostat *th, u8 addr)
-{
-	u8 tmp[2];
-	u16 res;
-	
-	/* should start with low byte */
-	tmp[1] = read_reg(th, addr);
-	tmp[0] = read_reg(th, addr + 1);
-	
-	res = tmp[1] + (tmp[0] << 8);
-	return (90000*60)/res;
-}
-
-static void write_both_fan_speed(struct thermostat *th, int speed)
-{
-	write_fan_speed(th, speed, 0);
-	if (therm_type == ADT7460)
-		write_fan_speed(th, speed, 1);
-}
-
-static void write_fan_speed(struct thermostat *th, int speed, int fan)
-{
-	u8 manual;
-	
-	if (speed > 0xff) 
-		speed = 0xff;
-	else if (speed < -1) 
-		speed = 0;
-	
-	if (therm_type == ADT7467 && fan == 1)
-		return;
-	
-	if (th->last_speed[fan] != speed) {
-		if (speed == -1)
-			printk(KERN_INFO "adt746x: Setting speed to: automatic for %s fan.\n",
-				fan?"GPU":"CPU");
-		else
-			printk(KERN_INFO "adt746x: Setting speed to: %d for %s fan.\n",
-				speed, fan?"GPU":"CPU");
-	} else
-		return;
-	
-	if (speed >= 0) {
-		manual = read_reg(th, MANUAL_MODE[fan]);
-		write_reg(th, MANUAL_MODE[fan], manual|MANUAL_MASK);
-		write_reg(th, FAN_SPD_SET[fan], speed);
-	} else {
-		/* back to automatic */
-		if(therm_type == ADT7460) {
-			manual = read_reg(th, MANUAL_MODE[fan]) & (~MANUAL_MASK);
-			write_reg(th, MANUAL_MODE[fan], manual|REM_CONTROL[fan]);
-		} else {
-			manual = read_reg(th, MANUAL_MODE[fan]);
-			write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK));
-		}
-	}
-	
-	th->last_speed[fan] = speed;			
-}
-
-static int monitor_task(void *arg)
-{
-	struct thermostat* th = arg;
-	u8 temps[3];
-	u8 lims[3];
-	int i;
-#ifdef DEBUG
-	int mfan_speed;
-#endif
-	
-	lock_kernel();
-	daemonize("kfand");
-	unlock_kernel();
-	strcpy(current->comm, "thermostat");
-	monitor_running = 1;
-
-	while(monitor_running)
-	{
-		set_task_state(current, TASK_UNINTERRUPTIBLE);
-		schedule_timeout(2*HZ);
-
-		/* Check status */
-		/* local   : chip */
-		/* remote 1: CPU ?*/
-		/* remote 2: GPU ?*/
-#ifndef DEBUG
-		if (fan_speed != -1) {
-#endif
-			for (i = 0; i < 3; i++) {
-				temps[i]  = read_reg(th, TEMP_REG[i]);
-				lims[i]   = th->limits[i];
-			}
-#ifndef DEBUG
-		}
-#endif		
-		if (fan_speed != -1) {
-			int lastvar = 0;		/* for iBook */
-			for (i = 1; i < 3; i++) {	/* we don't care about local sensor */
-				int started = 0;
-				int fan_number = (therm_type == ADT7460 && i == 2);
-				int var = temps[i] - lims[i];
-				if (var > 8) {
-					if (th->overriding[fan_number] == 0)
-						printk(KERN_INFO "adt746x: Limit exceeded by %d°C, overriding specified fan speed for %s.\n",
-							var, fan_number?"GPU":"CPU");
-					th->overriding[fan_number] = 1;
-					write_fan_speed(th, 255, fan_number);
-					started = 1;
-				} else if ((!th->overriding[fan_number] || var < 6) && var > 0) {
-					if (th->overriding[fan_number] == 1)
-						printk(KERN_INFO "adt746x: Limit exceeded by %d°C, setting speed to specified for %s.\n",
-							var, fan_number?"GPU":"CPU");					
-					th->overriding[fan_number] = 0;
-					write_fan_speed(th, fan_speed, fan_number);
-					started = 1;
-				} else if (var < -1) {
-					/* don't stop iBook fan if GPU is cold and CPU is not
-					 * so cold (lastvar >= -1) */
-					if (therm_type == ADT7460 || lastvar < -1 || i == 1) {
-						if (th->last_speed[fan_number] != 0)
-							printk(KERN_INFO "adt746x: Stopping %s fan.\n",
-								fan_number?"GPU":"CPU");
-						write_fan_speed(th, 0, fan_number);
-					}
-				}
-				
-				lastvar = var;
-				
-				if (started && therm_type == ADT7467)
-					break; /* we don't want to re-stop the fan
-						* if CPU is heating and GPU is not */
-			}
-		}
-#ifdef DEBUG
-		mfan_speed = read_fan_speed(th, FAN_SPEED[0]);
-		/* only one fan in the iBook G4 */
-				
-		if (temps[0] != th->cached_temp[0]
-		||  temps[1] != th->cached_temp[1]
-		||  temps[2] != th->cached_temp[2]) {
-			printk(KERN_INFO "adt746x: Temperature infos:"
-					 " thermostats: %d,%d,%d °C;"
-					 " limits: %d,%d,%d °C;"
-					 " fan speed: %d RPM\n",
-				temps[0], temps[1], temps[2],
-				lims[0],  lims[1],  lims[2],
-				mfan_speed);
-		}
-		th->cached_temp[0] = temps[0];
-		th->cached_temp[1] = temps[1];
-		th->cached_temp[2] = temps[2];
-#endif		
-	}
-
-	complete_and_exit(&monitor_task_compl, 0);
-	return 0;
-}
-
-static void
-set_limit(struct thermostat *th, int i)
-{
-		/* Set CPU limit higher to avoid powerdowns */ 
-		th->limits[i] = default_limits_chip[i] + limit_adjust;
-		write_reg(th, LIMIT_REG[i], th->limits[i]);
-		
-		/* set our limits to normal */
-		th->limits[i] = default_limits_local[i] + limit_adjust;
-}
-	
-static int
-attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno)
-{
-	struct thermostat* th;
-	int rc;
-	int i;
-
-	if (thermostat)
-		return 0;
-	th = (struct thermostat *)kmalloc(sizeof(struct thermostat), GFP_KERNEL);
-	if (!th)
-		return -ENOMEM;
-	memset(th, 0, sizeof(*th));
-	th->clt.addr = addr;
-	th->clt.adapter = adapter;
-	th->clt.driver = &thermostat_driver;
-	th->clt.id = 0xDEAD7467;
-	strcpy(th->clt.name, "thermostat");
-
-	rc = read_reg(th, 0);
-	if (rc < 0) {
-		printk(KERN_ERR "adt746x: Thermostat failed to read config from bus %d !\n",
-			busno);
-		kfree(th);
-		return -ENODEV;
-	}
-	/* force manual control to start the fan quieter */
-	
-	if (fan_speed == -1)
-		fan_speed=128;
-	
-	if(therm_type == ADT7460) {
-		printk(KERN_INFO "adt746x: ADT7460 initializing\n");
-		/* The 7460 needs to be started explicitly */
-		write_reg(th, CONFIG_REG, 1);
-	} else
-		printk(KERN_INFO "adt746x: ADT7467 initializing\n");
-
-	for (i = 0; i < 3; i++) {
-		th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
-		set_limit(th, i);
-	}
-	
-	printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
-		" to %d, %d, %d (°C)\n", 
-		th->initial_limits[0], th->initial_limits[1], th->initial_limits[2], 
-		th->limits[0], th->limits[1], th->limits[2]);
-
-	thermostat = th;
-
-	if (i2c_attach_client(&th->clt)) {
-		printk("adt746x: Thermostat failed to attach client !\n");
-		thermostat = NULL;
-		kfree(th);
-		return -ENODEV;
-	}
-
-	/* be sure to really write fan speed the first time */
-	th->last_speed[0] = -2;
-	th->last_speed[1] = -2;
-	
-	if (fan_speed != -1) {
-		write_both_fan_speed(th, 0);
-	} else {
-		write_both_fan_speed(th, -1);
-	}
-	
-	init_completion(&monitor_task_compl);
-	
-	monitor_thread_id = kernel_thread(monitor_task, th,
-		SIGCHLD | CLONE_KERNEL);
-
-	return 0;
-}
-
-/* 
- * Now, unfortunately, sysfs doesn't give us a nice void * we could
- * pass around to the attribute functions, so we don't really have
- * choice but implement a bunch of them...
- *
- */
-#define BUILD_SHOW_FUNC_DEG(name, data)				\
-static ssize_t show_##name(struct device *dev, char *buf)	\
-{								\
-	return sprintf(buf, "%d°C\n", data);			\
-}
-#define BUILD_SHOW_FUNC_INT(name, data)				\
-static ssize_t show_##name(struct device *dev, char *buf)	\
-{								\
-	return sprintf(buf, "%d\n", data);			\
-}
-
-#define BUILD_STORE_FUNC_DEG(name, data)			\
-static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \
-{								\
-	int val;						\
-	int i;							\
-	val = simple_strtol(buf, NULL, 10);			\
-	printk(KERN_INFO "Adjusting limits by %d°C\n", val);	\
-	limit_adjust = val;					\
-	for (i=0; i < 3; i++)					\
-		set_limit(thermostat, i);			\
-	return n;						\
-}
-
-#define BUILD_STORE_FUNC_INT(name, data)			\
-static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \
-{								\
-	u32 val;						\
-	val = simple_strtoul(buf, NULL, 10);			\
-	if (val < 0 || val > 255)				\
-		return -EINVAL;					\
-	printk(KERN_INFO "Setting fan speed to %d\n", val);	\
-	data = val;						\
-	return n;						\
-}
-
-BUILD_SHOW_FUNC_DEG(cpu_temperature,	 (read_reg(thermostat, TEMP_REG[1])))
-BUILD_SHOW_FUNC_DEG(gpu_temperature,	 (read_reg(thermostat, TEMP_REG[2])))
-BUILD_SHOW_FUNC_DEG(cpu_limit,		 thermostat->limits[1])
-BUILD_SHOW_FUNC_DEG(gpu_limit,		 thermostat->limits[2])
-
-BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
-BUILD_SHOW_FUNC_INT(cpu_fan_speed,	 (read_fan_speed(thermostat, FAN_SPEED[0])))
-BUILD_SHOW_FUNC_INT(gpu_fan_speed,	 (read_fan_speed(thermostat, FAN_SPEED[1])))
-
-BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
-BUILD_SHOW_FUNC_INT(limit_adjust,	 limit_adjust)
-BUILD_STORE_FUNC_DEG(limit_adjust,	 thermostat)
-		
-static DEVICE_ATTR(cpu_temperature,	S_IRUGO,
-		   show_cpu_temperature,NULL);
-static DEVICE_ATTR(gpu_temperature,	S_IRUGO,
-		   show_gpu_temperature,NULL);
-static DEVICE_ATTR(cpu_limit,		S_IRUGO,
-		   show_cpu_limit,	NULL);
-static DEVICE_ATTR(gpu_limit,		S_IRUGO,
-		   show_gpu_limit,	NULL);
-
-static DEVICE_ATTR(specified_fan_speed,	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
-		   show_specified_fan_speed,store_specified_fan_speed);
-
-static DEVICE_ATTR(cpu_fan_speed,	S_IRUGO,
-		   show_cpu_fan_speed,	NULL);
-static DEVICE_ATTR(gpu_fan_speed,	S_IRUGO,
-		   show_gpu_fan_speed,	NULL);
-
-static DEVICE_ATTR(limit_adjust,	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
-		   show_limit_adjust,	store_limit_adjust);
-
-
-static int __init
-thermostat_init(void)
-{
-	struct device_node* np;
-	u32 *prop;
-	
-	/* Currently, we only deal with the iBook G4, we will support
-	 * all "2003" powerbooks later on
-	 */
-	np = of_find_node_by_name(NULL, "fan");
-	if (!np)
-		return -ENODEV;
-	if (device_is_compatible(np, "adt7460"))
-		therm_type = ADT7460;
-	else if (device_is_compatible(np, "adt7467"))
-		therm_type = ADT7467;
-	else
-		return -ENODEV;
-
-	prop = (u32 *)get_property(np, "reg", NULL);
-	if (!prop)
-		return -ENODEV;
-	therm_bus = ((*prop) >> 8) & 0x0f;
-	therm_address = ((*prop) & 0xff) >> 1;
-
-	printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, limit_adjust: %d, fan_speed: %d\n",
-		therm_bus, therm_address, limit_adjust, fan_speed);
-
-	of_dev = of_platform_device_create(np, "temperatures");
-	
-	if (of_dev == NULL) {
-		printk(KERN_ERR "Can't register temperatures device !\n");
-		return -ENODEV;
-	}
-	
-	device_create_file(&of_dev->dev, &dev_attr_cpu_temperature);
-	device_create_file(&of_dev->dev, &dev_attr_gpu_temperature);
-	device_create_file(&of_dev->dev, &dev_attr_cpu_limit);
-	device_create_file(&of_dev->dev, &dev_attr_gpu_limit);
-	device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
-	device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-	device_create_file(&of_dev->dev, &dev_attr_cpu_fan_speed);
-	if(therm_type == ADT7460)
-		device_create_file(&of_dev->dev, &dev_attr_gpu_fan_speed);
-
-#ifndef CONFIG_I2C_KEYWEST
-	request_module("i2c-keywest");
-#endif
-
-	return i2c_add_driver(&thermostat_driver);
-}
-
-static void __exit
-thermostat_exit(void)
-{
-	if (of_dev) {
-		device_remove_file(&of_dev->dev, &dev_attr_cpu_temperature);
-		device_remove_file(&of_dev->dev, &dev_attr_gpu_temperature);
-		device_remove_file(&of_dev->dev, &dev_attr_cpu_limit);
-		device_remove_file(&of_dev->dev, &dev_attr_gpu_limit);
-		device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
-		device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
-		device_remove_file(&of_dev->dev, &dev_attr_cpu_fan_speed);
-		if(therm_type == ADT7460)
-			device_remove_file(&of_dev->dev, &dev_attr_gpu_fan_speed);
-		of_device_unregister(of_dev);
-	}
-	i2c_del_driver(&thermostat_driver);
-}
-
-module_init(thermostat_init);
-module_exit(thermostat_exit);
diff -Nru a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/macintosh/therm_adt746x.c	Sat Apr  3 19:38:54 2004
@@ -0,0 +1,559 @@
+/*
+ * Device driver for the i2c thermostat found on the iBook G4, Albook G4
+ *
+ * Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt
+ *
+ * Documentation from
+ * http://www.analog.com/UploadedFiles/Data_Sheets/115254175ADT7467_pra.pdf
+ * http://www.analog.com/UploadedFiles/Data_Sheets/3686221171167ADT7460_b.pdf
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/of_device.h>
+
+#undef DEBUG
+
+#define CONFIG_REG   0x40
+#define MANUAL_MASK  0xe0
+#define AUTO_MASK    0x20
+
+static u8 TEMP_REG[3]    = {0x26, 0x25, 0x27}; /* local, cpu, gpu */
+static u8 LIMIT_REG[3]   = {0x6b, 0x6a, 0x6c}; /* local, cpu, gpu */
+static u8 MANUAL_MODE[2] = {0x5c, 0x5d};       
+static u8 REM_CONTROL[2] = {0x00, 0x40};
+static u8 FAN_SPEED[2]   = {0x28, 0x2a};
+static u8 FAN_SPD_SET[2] = {0x30, 0x31};
+
+static u8 default_limits_local[3] = {70, 50, 70};    /* local, cpu, gpu */
+static u8 default_limits_chip[3] = {80, 65, 80};    /* local, cpu, gpu */
+
+static int limit_adjust = 0;
+static int fan_speed = -1;
+
+MODULE_AUTHOR("Colin Leroy <colin@colino.net>");
+MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and Powerbook G4 Alu");
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(limit_adjust,"i");
+MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50°C cpu, 70°C gpu) by N °C.");
+MODULE_PARM(fan_speed,"i");
+MODULE_PARM_DESC(fan_speed,"Specify fan speed (0-255) when lim < temp < lim+8 (default 128)");
+
+struct thermostat {
+	struct i2c_client	clt;
+	u8			cached_temp[3];
+	u8			initial_limits[3];
+	u8			limits[3];
+	int			last_speed[2];
+	int			overriding[2];
+};
+
+static enum {ADT7460, ADT7467} therm_type;
+static int therm_bus, therm_address;
+static struct of_device * of_dev;
+static struct thermostat* thermostat;
+static pid_t monitor_thread_id;
+static int monitor_running;
+static struct completion monitor_task_compl;
+
+static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno);
+static void write_both_fan_speed(struct thermostat *th, int speed);
+static void write_fan_speed(struct thermostat *th, int speed, int fan);
+
+static int
+write_reg(struct thermostat* th, int reg, u8 data)
+{
+	u8 tmp[2];
+	int rc;
+	
+	tmp[0] = reg;
+	tmp[1] = data;
+	rc = i2c_master_send(&th->clt, (const char *)tmp, 2);
+	if (rc < 0)
+		return rc;
+	if (rc != 2)
+		return -ENODEV;
+	return 0;
+}
+
+static int
+read_reg(struct thermostat* th, int reg)
+{
+	u8 reg_addr, data;
+	int rc;
+
+	reg_addr = (u8)reg;
+	rc = i2c_master_send(&th->clt, &reg_addr, 1);
+	if (rc < 0)
+		return rc;
+	if (rc != 1)
+		return -ENODEV;
+	rc = i2c_master_recv(&th->clt, (char *)&data, 1);
+	if (rc < 0)
+		return rc;
+	return data;
+}
+
+static int
+attach_thermostat(struct i2c_adapter *adapter)
+{
+	unsigned long bus_no;
+
+	if (strncmp(adapter->name, "uni-n", 5))
+		return -ENODEV;
+	bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
+	if (bus_no != therm_bus)
+		return -ENODEV;
+	return attach_one_thermostat(adapter, therm_address, bus_no);
+}
+
+static int
+detach_thermostat(struct i2c_adapter *adapter)
+{
+	struct thermostat* th;
+	int i;
+	
+	if (thermostat == NULL)
+		return 0;
+
+	th = thermostat;
+
+	if (monitor_running) {
+		monitor_running = 0;
+		wait_for_completion(&monitor_task_compl);
+	}
+		
+	printk(KERN_INFO "adt746x: Putting max temperatures back from %d, %d, %d,"
+		" to %d, %d, %d, (°C)\n", 
+		th->limits[0], th->limits[1], th->limits[2],
+		th->initial_limits[0], th->initial_limits[1], th->initial_limits[2]);
+	
+	for (i = 0; i < 3; i++)
+		write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
+
+	write_both_fan_speed(th, -1);
+
+	i2c_detach_client(&th->clt);
+
+	thermostat = NULL;
+
+	kfree(th);
+
+	return 0;
+}
+
+static struct i2c_driver thermostat_driver = {  
+	.name		="Apple Thermostat ADT746x",
+	.id		=0xDEAD7467,
+	.flags		=I2C_DF_NOTIFY,
+	.attach_adapter	=&attach_thermostat,
+	.detach_adapter	=&detach_thermostat,
+};
+
+static int read_fan_speed(struct thermostat *th, u8 addr)
+{
+	u8 tmp[2];
+	u16 res;
+	
+	/* should start with low byte */
+	tmp[1] = read_reg(th, addr);
+	tmp[0] = read_reg(th, addr + 1);
+	
+	res = tmp[1] + (tmp[0] << 8);
+	return (90000*60)/res;
+}
+
+static void write_both_fan_speed(struct thermostat *th, int speed)
+{
+	write_fan_speed(th, speed, 0);
+	if (therm_type == ADT7460)
+		write_fan_speed(th, speed, 1);
+}
+
+static void write_fan_speed(struct thermostat *th, int speed, int fan)
+{
+	u8 manual;
+	
+	if (speed > 0xff) 
+		speed = 0xff;
+	else if (speed < -1) 
+		speed = 0;
+	
+	if (therm_type == ADT7467 && fan == 1)
+		return;
+	
+	if (th->last_speed[fan] != speed) {
+		if (speed == -1)
+			printk(KERN_INFO "adt746x: Setting speed to: automatic for %s fan.\n",
+				fan?"GPU":"CPU");
+		else
+			printk(KERN_INFO "adt746x: Setting speed to: %d for %s fan.\n",
+				speed, fan?"GPU":"CPU");
+	} else
+		return;
+	
+	if (speed >= 0) {
+		manual = read_reg(th, MANUAL_MODE[fan]);
+		write_reg(th, MANUAL_MODE[fan], manual|MANUAL_MASK);
+		write_reg(th, FAN_SPD_SET[fan], speed);
+	} else {
+		/* back to automatic */
+		if(therm_type == ADT7460) {
+			manual = read_reg(th, MANUAL_MODE[fan]) & (~MANUAL_MASK);
+			write_reg(th, MANUAL_MODE[fan], manual|REM_CONTROL[fan]);
+		} else {
+			manual = read_reg(th, MANUAL_MODE[fan]);
+			write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK));
+		}
+	}
+	
+	th->last_speed[fan] = speed;			
+}
+
+static int monitor_task(void *arg)
+{
+	struct thermostat* th = arg;
+	u8 temps[3];
+	u8 lims[3];
+	int i;
+#ifdef DEBUG
+	int mfan_speed;
+#endif
+	
+	lock_kernel();
+	daemonize("kfand");
+	unlock_kernel();
+	strcpy(current->comm, "thermostat");
+	monitor_running = 1;
+
+	while(monitor_running)
+	{
+		set_task_state(current, TASK_UNINTERRUPTIBLE);
+		schedule_timeout(2*HZ);
+
+		/* Check status */
+		/* local   : chip */
+		/* remote 1: CPU ?*/
+		/* remote 2: GPU ?*/
+#ifndef DEBUG
+		if (fan_speed != -1) {
+#endif
+			for (i = 0; i < 3; i++) {
+				temps[i]  = read_reg(th, TEMP_REG[i]);
+				lims[i]   = th->limits[i];
+			}
+#ifndef DEBUG
+		}
+#endif		
+		if (fan_speed != -1) {
+			int lastvar = 0;		/* for iBook */
+			for (i = 1; i < 3; i++) {	/* we don't care about local sensor */
+				int started = 0;
+				int fan_number = (therm_type == ADT7460 && i == 2);
+				int var = temps[i] - lims[i];
+				if (var > 8) {
+					if (th->overriding[fan_number] == 0)
+						printk(KERN_INFO "adt746x: Limit exceeded by %d°C, overriding specified fan speed for %s.\n",
+							var, fan_number?"GPU":"CPU");
+					th->overriding[fan_number] = 1;
+					write_fan_speed(th, 255, fan_number);
+					started = 1;
+				} else if ((!th->overriding[fan_number] || var < 6) && var > 0) {
+					if (th->overriding[fan_number] == 1)
+						printk(KERN_INFO "adt746x: Limit exceeded by %d°C, setting speed to specified for %s.\n",
+							var, fan_number?"GPU":"CPU");					
+					th->overriding[fan_number] = 0;
+					write_fan_speed(th, fan_speed, fan_number);
+					started = 1;
+				} else if (var < -1) {
+					/* don't stop iBook fan if GPU is cold and CPU is not
+					 * so cold (lastvar >= -1) */
+					if (therm_type == ADT7460 || lastvar < -1 || i == 1) {
+						if (th->last_speed[fan_number] != 0)
+							printk(KERN_INFO "adt746x: Stopping %s fan.\n",
+								fan_number?"GPU":"CPU");
+						write_fan_speed(th, 0, fan_number);
+					}
+				}
+				
+				lastvar = var;
+				
+				if (started && therm_type == ADT7467)
+					break; /* we don't want to re-stop the fan
+						* if CPU is heating and GPU is not */
+			}
+		}
+#ifdef DEBUG
+		mfan_speed = read_fan_speed(th, FAN_SPEED[0]);
+		/* only one fan in the iBook G4 */
+				
+		if (temps[0] != th->cached_temp[0]
+		||  temps[1] != th->cached_temp[1]
+		||  temps[2] != th->cached_temp[2]) {
+			printk(KERN_INFO "adt746x: Temperature infos:"
+					 " thermostats: %d,%d,%d °C;"
+					 " limits: %d,%d,%d °C;"
+					 " fan speed: %d RPM\n",
+				temps[0], temps[1], temps[2],
+				lims[0],  lims[1],  lims[2],
+				mfan_speed);
+		}
+		th->cached_temp[0] = temps[0];
+		th->cached_temp[1] = temps[1];
+		th->cached_temp[2] = temps[2];
+#endif		
+	}
+
+	complete_and_exit(&monitor_task_compl, 0);
+	return 0;
+}
+
+static void
+set_limit(struct thermostat *th, int i)
+{
+		/* Set CPU limit higher to avoid powerdowns */ 
+		th->limits[i] = default_limits_chip[i] + limit_adjust;
+		write_reg(th, LIMIT_REG[i], th->limits[i]);
+		
+		/* set our limits to normal */
+		th->limits[i] = default_limits_local[i] + limit_adjust;
+}
+	
+static int
+attach_one_thermostat(struct i2c_adapter *adapter, int addr, int busno)
+{
+	struct thermostat* th;
+	int rc;
+	int i;
+
+	if (thermostat)
+		return 0;
+	th = (struct thermostat *)kmalloc(sizeof(struct thermostat), GFP_KERNEL);
+	if (!th)
+		return -ENOMEM;
+	memset(th, 0, sizeof(*th));
+	th->clt.addr = addr;
+	th->clt.adapter = adapter;
+	th->clt.driver = &thermostat_driver;
+	th->clt.id = 0xDEAD7467;
+	strcpy(th->clt.name, "thermostat");
+
+	rc = read_reg(th, 0);
+	if (rc < 0) {
+		printk(KERN_ERR "adt746x: Thermostat failed to read config from bus %d !\n",
+			busno);
+		kfree(th);
+		return -ENODEV;
+	}
+	/* force manual control to start the fan quieter */
+	
+	if (fan_speed == -1)
+		fan_speed=128;
+	
+	if(therm_type == ADT7460) {
+		printk(KERN_INFO "adt746x: ADT7460 initializing\n");
+		/* The 7460 needs to be started explicitly */
+		write_reg(th, CONFIG_REG, 1);
+	} else
+		printk(KERN_INFO "adt746x: ADT7467 initializing\n");
+
+	for (i = 0; i < 3; i++) {
+		th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
+		set_limit(th, i);
+	}
+	
+	printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
+		" to %d, %d, %d (°C)\n", 
+		th->initial_limits[0], th->initial_limits[1], th->initial_limits[2], 
+		th->limits[0], th->limits[1], th->limits[2]);
+
+	thermostat = th;
+
+	if (i2c_attach_client(&th->clt)) {
+		printk("adt746x: Thermostat failed to attach client !\n");
+		thermostat = NULL;
+		kfree(th);
+		return -ENODEV;
+	}
+
+	/* be sure to really write fan speed the first time */
+	th->last_speed[0] = -2;
+	th->last_speed[1] = -2;
+	
+	if (fan_speed != -1) {
+		write_both_fan_speed(th, 0);
+	} else {
+		write_both_fan_speed(th, -1);
+	}
+	
+	init_completion(&monitor_task_compl);
+	
+	monitor_thread_id = kernel_thread(monitor_task, th,
+		SIGCHLD | CLONE_KERNEL);
+
+	return 0;
+}
+
+/* 
+ * Now, unfortunately, sysfs doesn't give us a nice void * we could
+ * pass around to the attribute functions, so we don't really have
+ * choice but implement a bunch of them...
+ *
+ */
+#define BUILD_SHOW_FUNC_DEG(name, data)				\
+static ssize_t show_##name(struct device *dev, char *buf)	\
+{								\
+	return sprintf(buf, "%d°C\n", data);			\
+}
+#define BUILD_SHOW_FUNC_INT(name, data)				\
+static ssize_t show_##name(struct device *dev, char *buf)	\
+{								\
+	return sprintf(buf, "%d\n", data);			\
+}
+
+#define BUILD_STORE_FUNC_DEG(name, data)			\
+static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \
+{								\
+	int val;						\
+	int i;							\
+	val = simple_strtol(buf, NULL, 10);			\
+	printk(KERN_INFO "Adjusting limits by %d°C\n", val);	\
+	limit_adjust = val;					\
+	for (i=0; i < 3; i++)					\
+		set_limit(thermostat, i);			\
+	return n;						\
+}
+
+#define BUILD_STORE_FUNC_INT(name, data)			\
+static ssize_t store_##name(struct device *dev, const char *buf, size_t n) \
+{								\
+	u32 val;						\
+	val = simple_strtoul(buf, NULL, 10);			\
+	if (val < 0 || val > 255)				\
+		return -EINVAL;					\
+	printk(KERN_INFO "Setting fan speed to %d\n", val);	\
+	data = val;						\
+	return n;						\
+}
+
+BUILD_SHOW_FUNC_DEG(cpu_temperature,	 (read_reg(thermostat, TEMP_REG[1])))
+BUILD_SHOW_FUNC_DEG(gpu_temperature,	 (read_reg(thermostat, TEMP_REG[2])))
+BUILD_SHOW_FUNC_DEG(cpu_limit,		 thermostat->limits[1])
+BUILD_SHOW_FUNC_DEG(gpu_limit,		 thermostat->limits[2])
+
+BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
+BUILD_SHOW_FUNC_INT(cpu_fan_speed,	 (read_fan_speed(thermostat, FAN_SPEED[0])))
+BUILD_SHOW_FUNC_INT(gpu_fan_speed,	 (read_fan_speed(thermostat, FAN_SPEED[1])))
+
+BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
+BUILD_SHOW_FUNC_INT(limit_adjust,	 limit_adjust)
+BUILD_STORE_FUNC_DEG(limit_adjust,	 thermostat)
+		
+static DEVICE_ATTR(cpu_temperature,	S_IRUGO,
+		   show_cpu_temperature,NULL);
+static DEVICE_ATTR(gpu_temperature,	S_IRUGO,
+		   show_gpu_temperature,NULL);
+static DEVICE_ATTR(cpu_limit,		S_IRUGO,
+		   show_cpu_limit,	NULL);
+static DEVICE_ATTR(gpu_limit,		S_IRUGO,
+		   show_gpu_limit,	NULL);
+
+static DEVICE_ATTR(specified_fan_speed,	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
+		   show_specified_fan_speed,store_specified_fan_speed);
+
+static DEVICE_ATTR(cpu_fan_speed,	S_IRUGO,
+		   show_cpu_fan_speed,	NULL);
+static DEVICE_ATTR(gpu_fan_speed,	S_IRUGO,
+		   show_gpu_fan_speed,	NULL);
+
+static DEVICE_ATTR(limit_adjust,	S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
+		   show_limit_adjust,	store_limit_adjust);
+
+
+static int __init
+thermostat_init(void)
+{
+	struct device_node* np;
+	u32 *prop;
+	
+	np = of_find_node_by_name(NULL, "fan");
+	if (!np)
+		return -ENODEV;
+	if (device_is_compatible(np, "adt7460"))
+		therm_type = ADT7460;
+	else if (device_is_compatible(np, "adt7467"))
+		therm_type = ADT7467;
+	else
+		return -ENODEV;
+
+	prop = (u32 *)get_property(np, "reg", NULL);
+	if (!prop)
+		return -ENODEV;
+	therm_bus = ((*prop) >> 8) & 0x0f;
+	therm_address = ((*prop) & 0xff) >> 1;
+
+	printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, limit_adjust: %d, fan_speed: %d\n",
+		therm_bus, therm_address, limit_adjust, fan_speed);
+
+	of_dev = of_platform_device_create(np, "temperatures");
+	
+	if (of_dev == NULL) {
+		printk(KERN_ERR "Can't register temperatures device !\n");
+		return -ENODEV;
+	}
+	
+	device_create_file(&of_dev->dev, &dev_attr_cpu_temperature);
+	device_create_file(&of_dev->dev, &dev_attr_gpu_temperature);
+	device_create_file(&of_dev->dev, &dev_attr_cpu_limit);
+	device_create_file(&of_dev->dev, &dev_attr_gpu_limit);
+	device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
+	device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
+	device_create_file(&of_dev->dev, &dev_attr_cpu_fan_speed);
+	if(therm_type == ADT7460)
+		device_create_file(&of_dev->dev, &dev_attr_gpu_fan_speed);
+
+#ifndef CONFIG_I2C_KEYWEST
+	request_module("i2c-keywest");
+#endif
+
+	return i2c_add_driver(&thermostat_driver);
+}
+
+static void __exit
+thermostat_exit(void)
+{
+	if (of_dev) {
+		device_remove_file(&of_dev->dev, &dev_attr_cpu_temperature);
+		device_remove_file(&of_dev->dev, &dev_attr_gpu_temperature);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu_limit);
+		device_remove_file(&of_dev->dev, &dev_attr_gpu_limit);
+		device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
+		device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu_fan_speed);
+		if(therm_type == ADT7460)
+			device_remove_file(&of_dev->dev, &dev_attr_gpu_fan_speed);
+		of_device_unregister(of_dev);
+	}
+	i2c_del_driver(&thermostat_driver);
+}
+
+module_init(thermostat_init);
+module_exit(thermostat_exit);
diff -Nru a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
--- a/drivers/macintosh/therm_pm72.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/macintosh/therm_pm72.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 /*
  * 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 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
+	 */
+
+	/* 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 ctrl;
+	int rc, data, tries = 0;
+	u8 buf[2];
 
-	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;
+	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 @@
 	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 @@
 	 * 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 @@
 	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,8 +1016,17 @@
 
 	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 -Nru a/drivers/macintosh/therm_pm72.h b/drivers/macintosh/therm_pm72.h
--- a/drivers/macintosh/therm_pm72.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/macintosh/therm_pm72.h	Sat Apr  3 19:38:43 2004
@@ -85,7 +85,7 @@
  * 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 @@
 	s32			current_a;
 	s32			last_temp;
 	int			first;
+	u8			adc_config;
 };
 
 /*
diff -Nru a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
--- a/drivers/macintosh/therm_windtunnel.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/macintosh/therm_windtunnel.c	Sat Apr  3 19:38:54 2004
@@ -1,24 +1,23 @@
 /* 
  *   Creation Date: <2003/03/14 20:54:13 samuel>
- *   Time-stamp: <2003/03/15 18:55:53 samuel>
+ *   Time-stamp: <2004/03/20 14:20:59 samuel>
  *   
  *	<therm_windtunnel.c>
  *	
- *	The G4 "windtunnel" has a single fan controlled by a
- *	DS1775 fan controller and an ADM1030 thermostat.
+ *	The G4 "windtunnel" has a single fan controlled by an
+ *	ADM1030 fan controller and a DS1775 thermostat.
  *
  *	The fan controller is equipped with a temperature sensor
- *	which measures the case temperature. The ADM censor
+ *	which measures the case temperature. The DS1775 sensor
  *	measures the CPU temperature. This driver tunes the
  *	behavior of the fan. It is based upon empirical observations
- *	of the 'AppleFan' driver under OSX.
+ *	of the 'AppleFan' driver under Mac OS X.
  *
  *	WARNING: This driver has only been testen on Apple's
- *	1.25 MHz Dual G4 (March 03). Other machines might have
- *	a different thermal design. It is tuned for a CPU
+ *	1.25 MHz Dual G4 (March 03). It is tuned for a CPU
  *	temperatur around 57 C.
  *
- *   Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
+ *   Copyright (C) 2003, 2004 Samuel Rydh (samuel@ibrium.se)
  *
  *   Loosely based upon 'thermostat.c' written by Benjamin Herrenschmidt
  *   
@@ -38,50 +37,37 @@
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/workqueue.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/sections.h>
-
-MODULE_AUTHOR("Samuel Rydh <samuel@ibrium.se>");
-MODULE_DESCRIPTION("Apple G4 (windtunnel) fan driver");
-MODULE_LICENSE("GPL");
+#include <asm/of_device.h>
 
 #define LOG_TEMP		0			/* continously log temperature */
 
-/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
-static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END };
-static struct work_struct poll_work;
-
-I2C_CLIENT_INSMOD;
-
 #define I2C_DRIVERID_G4FAN	0x9001			/* fixme */
-
 #define THERMOSTAT_CLIENT_ID	1
 #define FAN_CLIENT_ID		2
 
-struct temp_range {
-	u8			high;			/* start the fan */
-	u8			low;			/* stop the fan */
-};
-struct apple_thermal_info {
-	u8			id;			/* implementation ID */
-	u8			fan_count;		/* number of fans */
-	u8			thermostat_count;	/* number of thermostats */
-	u8			unused[5];
-	struct temp_range	ranges[4];		/* temperature ranges (may be [])*/
-};
+static int 			do_probe( struct i2c_adapter *adapter, int addr, int kind);
 
-static int do_detect( struct i2c_adapter *adapter, int addr, int kind);
+/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
+static unsigned short		normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END };
+static unsigned short		normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
 
 static struct {
+	volatile int		running;
+	struct completion	completion;
+	pid_t			poll_task;
+	
+	struct semaphore 	lock;
+	struct of_device	*of_dev;
+	
 	struct i2c_client	*thermostat;
 	struct i2c_client	*fan;
-	int			error;
-	struct timer_list	timer;
 
 	int			overheat_temp;		/* 100% fan at this temp */
 	int			overheat_hyst;
@@ -95,37 +81,54 @@
 	int			r0, r1, r20, r23, r25;	/* saved register */
 } x;
 
+#define T(x,y)			(((x)<<8) | (y)*0x100/10 )
+
 static struct {
+	int			fan_down_setting;
 	int			temp;
-	int			fan_setting;
-} fan_up_table[] = {
-	{ 0x0000, 11 },		/* min fan */
-	{ 0x3900, 8 },		/* 57.0 C */
-	{ 0x3a4a, 7 },		/* 58.3 C */
-	{ 0x3ad3, 6 },		/* 58.8 C */
-	{ 0x3b3c, 5 },		/* 59.2 C */
-	{ 0x3b94, 4 },		/* 59.6 C */
-	{ 0x3be3, 3 },		/* 58.9 C */
-	{ 0x3c29, 2 },		/* 59.2 C */
-	{ 0xffff, 1 }		/* on fire */
-};
-static struct {
-	int			temp;
-	int			fan_setting;
-} fan_down_table[] = {
-	{ 0x3700, 11 },		/* 55.0 C */
-	{ 0x374a, 6 },
-	{ 0x3800, 7 },		/* 56.0 C */
-	{ 0x3900, 8 },		/* 57.0 C */
-	{ 0x3a4a, 7 },		/* 58.3 C */
-	{ 0x3ad3, 6 },		/* 58.8 C */
-	{ 0x3b3c, 5 },		/* 59.2 C */
-	{ 0x3b94, 4 },		/* 58.9 C */
-	{ 0x3be3, 3 },		/* 58.9 C */
-	{ 0x3c29, 2 },		/* 59.2 C */
-	{ 0xffff, 1 }
+	int			fan_up_setting;
+} fan_table[] = {
+	{ 11, T(0,0),  11 },	/* min fan */
+	{ 11, T(55,0), 11 },
+	{  6, T(55,3), 11 },
+	{  7, T(56,0), 11 },
+	{  8, T(57,0), 8 },
+	{  7, T(58,3), 7 },
+	{  6, T(58,8), 6 },
+	{  5, T(59,2), 5 },
+	{  4, T(59,6), 4 },
+	{  3, T(59,9), 3 },
+	{  2, T(60,1), 2 },
+	{  1, 0xfffff, 1 }	/* on fire */
 };
 
+static void
+print_temp( const char *s, int temp )
+{
+	printk("%s%d.%d C", s ? s : "", temp>>8, (temp & 255)*10/256 );
+}
+
+static ssize_t
+show_cpu_temperature( struct device *dev, char *buf )
+{
+	return sprintf(buf, "%d.%d\n", x.temp>>8, (x.temp & 255)*10/256 );
+}
+
+static ssize_t
+show_case_temperature( struct device *dev, char *buf )
+{
+	return sprintf(buf, "%d.%d\n", x.casetemp>>8, (x.casetemp & 255)*10/256 );
+}
+
+static DEVICE_ATTR(cpu_temperature, S_IRUGO, show_cpu_temperature, NULL );
+static DEVICE_ATTR(case_temperature, S_IRUGO, show_case_temperature, NULL );
+
+
+
+/************************************************************************/
+/*	controller thread						*/
+/************************************************************************/
+
 static int
 write_reg( struct i2c_client *cl, int reg, int data, int len )
 {
@@ -159,37 +162,32 @@
 	return (len == 2)? ((unsigned int)buf[0] << 8) | buf[1] : buf[0];
 }
 
-
-static void
-print_temp( const char *s, int temp )
-{
-	printk("%s%d.%d C", s ? s : "", temp>>8, (temp & 255)*10/256 );
-}
-
 static void
 tune_fan( int fan_setting )
 {
 	int val = (fan_setting << 3) | 7;
-	x.fan_level = fan_setting;
-	
-	//write_reg( x.fan, 0x24, val, 1 );
+
+	/* write_reg( x.fan, 0x24, val, 1 ); */
 	write_reg( x.fan, 0x25, val, 1 );
 	write_reg( x.fan, 0x20, 0, 1 );
 	print_temp("CPU-temp: ", x.temp );
 	if( x.casetemp )
 		print_temp(", Case: ", x.casetemp );
-	printk("  Tuning fan: %d (%02x)\n", fan_setting, val );
+	printk(",  Fan: %d (tuned %+d)\n", 11-fan_setting, x.fan_level-fan_setting );
+
+	x.fan_level = fan_setting;
 }
 
 static void
-poll_temp( void *param )
+poll_temp( void )
 {
-	int temp = read_reg( x.thermostat, 0, 2 );
-	int i, level, casetemp;
+	int temp, i, level, casetemp;
+
+	temp = read_reg( x.thermostat, 0, 2 );
 
 	/* this actually occurs when the computer is loaded */
 	if( temp < 0 )
-		goto out;
+		return;
 
 	casetemp = read_reg(x.fan, 0x0b, 1) << 8;
 	casetemp |= (read_reg(x.fan, 0x06, 1) & 0x7) << 5;
@@ -197,37 +195,117 @@
 	if( LOG_TEMP && x.temp != temp ) {
 		print_temp("CPU-temp: ", temp );
 		print_temp(", Case: ", casetemp );
-		printk(",  Fan: %d\n", x.fan_level );
+		printk(",  Fan: %d\n", 11-x.fan_level );
 	}
 	x.temp = temp;
 	x.casetemp = casetemp;
 
 	level = -1;
-	for( i=0; (temp & 0xffff) > fan_down_table[i].temp ; i++ )
+	for( i=0; (temp & 0xffff) > fan_table[i].temp ; i++ )
 		;
 	if( i < x.downind )
-		level = fan_down_table[i].fan_setting;
+		level = fan_table[i].fan_down_setting;
 	x.downind = i;
 
-	for( i=0; (temp & 0xfffe) >= fan_up_table[i+1].temp ; i++ )
+	for( i=0; (temp & 0xffff) >= fan_table[i+1].temp ; i++ )
 		;
 	if( x.upind < i )
-		level = fan_up_table[i].fan_setting;
+		level = fan_table[i].fan_up_setting;
 	x.upind = i;
 
 	if( level >= 0 )
 		tune_fan( level );
- out:
-	x.timer.expires = jiffies + 8*HZ;
-	add_timer( &x.timer );
+}
+
+
+static void
+setup_hardware( void )
+{
+	int val;
+
+	/* save registers (if we unload the module) */
+	x.r0 = read_reg( x.fan, 0x00, 1 );
+	x.r1 = read_reg( x.fan, 0x01, 1 );
+	x.r20 = read_reg( x.fan, 0x20, 1 );
+	x.r23 = read_reg( x.fan, 0x23, 1 );
+	x.r25 = read_reg( x.fan, 0x25, 1 );
+
+	/* improve measurement resolution (convergence time 1.5s) */
+	if( (val=read_reg(x.thermostat, 1, 1)) >= 0 ) {
+		val |= 0x60;
+		if( write_reg( x.thermostat, 1, val, 1 ) )
+			printk("Failed writing config register\n");
+	}
+	/* disable interrupts and TAC input */
+	write_reg( x.fan, 0x01, 0x01, 1 );
+	/* enable filter */
+	write_reg( x.fan, 0x23, 0x91, 1 );
+	/* remote temp. controls fan */
+	write_reg( x.fan, 0x00, 0x95, 1 );
+
+	/* The thermostat (which besides measureing temperature controls
+	 * has a THERM output which puts the fan on 100%) is usually
+	 * set to kick in at 80 C (chip default). We reduce this a bit
+	 * to be on the safe side (OSX doesn't)...
+	 */
+	if( x.overheat_temp == (80 << 8) ) {
+		x.overheat_temp = 65 << 8;
+		x.overheat_hyst = 60 << 8;
+		write_reg( x.thermostat, 2, x.overheat_hyst, 2 );
+		write_reg( x.thermostat, 3, x.overheat_temp, 2 );
+
+		print_temp("Reducing overheating limit to ", x.overheat_temp );
+		print_temp(" (Hyst: ", x.overheat_hyst );
+		printk(")\n");
+	}
+
+	/* set an initial fan setting */
+	x.downind = 0xffff;
+	x.upind = -1;
+	/* tune_fan( fan_up_table[x.upind].fan_setting ); */
+
+	device_create_file( &x.of_dev->dev, &dev_attr_cpu_temperature );
+	device_create_file( &x.of_dev->dev, &dev_attr_case_temperature );
 }
 
 static void
-schedule_poll( unsigned long t )
+restore_regs( void )
 {
-	schedule_work(&poll_work);
+	device_remove_file( &x.of_dev->dev, &dev_attr_cpu_temperature );
+	device_remove_file( &x.of_dev->dev, &dev_attr_case_temperature );
+
+	write_reg( x.fan, 0x01, x.r1, 1 );
+	write_reg( x.fan, 0x20, x.r20, 1 );
+	write_reg( x.fan, 0x23, x.r23, 1 );
+	write_reg( x.fan, 0x25, x.r25, 1 );
+	write_reg( x.fan, 0x00, x.r0, 1 );
 }
 
+static int
+control_loop( void *dummy )
+{
+	daemonize("g4fand");
+
+	down( &x.lock );
+	setup_hardware();
+
+	while( x.running ) {
+		up( &x.lock );
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout( 8*HZ );
+		
+		down( &x.lock );
+		poll_temp();
+	}
+
+	restore_regs();
+	up( &x.lock );
+
+	complete_and_exit( &x.completion, 0 );
+}
+
+
 /************************************************************************/
 /*	i2c probing and setup						*/
 /************************************************************************/
@@ -235,7 +313,20 @@
 static int
 do_attach( struct i2c_adapter *adapter )
 {
-	return i2c_probe( adapter, &addr_data, &do_detect );
+	int ret = 0;
+
+	if( strncmp(adapter->name, "uni-n", 5) )
+		return 0;
+
+	if( !x.running ) {
+		ret = i2c_probe( adapter, &addr_data, &do_probe );
+		if( x.thermostat && x.fan ) {
+			x.running = 1;
+			init_completion( &x.completion );
+			x.poll_task = kernel_thread( control_loop, NULL, SIGCHLD | CLONE_KERNEL );
+		}
+	}
+	return ret;
 }
 
 static int
@@ -243,13 +334,23 @@
 {
 	int err;
 
-	printk("do_detach: id %d\n", client->id );
-	if( (err=i2c_detach_client(client)) ) {
-		printk("failed to detach thermostat client\n");
-		return err;
+	if( (err=i2c_detach_client(client)) )
+		printk(KERN_ERR "failed to detach thermostat client\n");
+	else {
+		if( x.running ) {
+			x.running = 0;
+			wait_for_completion( &x.completion );
+		}
+		if( client == x.thermostat )
+			x.thermostat = NULL;
+		else if( client == x.fan )
+			x.fan = NULL;
+		else {
+			printk(KERN_ERR "g4fan: bad client\n");
+		}
+		kfree( client );
 	}
-	kfree( client );
-	return 0;
+	return err;
 }
 
 static struct i2c_driver g4fan_driver = {  
@@ -262,24 +363,21 @@
 };
 
 static int
-detect_fan( struct i2c_client *cl )
+attach_fan( struct i2c_client *cl )
 {
+	if( x.fan )
+		goto out;
+
 	/* check that this is an ADM1030 */
 	if( read_reg(cl, 0x3d, 1) != 0x30 || read_reg(cl, 0x3e, 1) != 0x41 )
 		goto out;
-	printk("ADM1030 fan controller detected at %02x\n", cl->addr );
+	printk("ADM1030 fan controller [@%02x]\n", cl->addr );
 
-	if( x.fan ) {
-		x.error |= 2;
-		goto out;
-	}
-	x.fan = cl;
 	cl->id = FAN_CLIENT_ID;
-	strncpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) );
+	strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) );
 
-	if( i2c_attach_client( cl ) )
-		goto out;
-	return 0;
+	if( !i2c_attach_client(cl) )
+		x.fan = cl;
  out:
 	if( cl != x.fan )
 		kfree( cl );
@@ -287,10 +385,13 @@
 }
 
 static int
-detect_thermostat( struct i2c_client *cl ) 
+attach_thermostat( struct i2c_client *cl ) 
 {
 	int hyst_temp, os_temp, temp;
 
+	if( x.thermostat )
+		goto out;
+
 	if( (temp=read_reg(cl, 0, 2)) < 0 )
 		goto out;
 	
@@ -302,44 +403,37 @@
 	if( hyst_temp < 0 || os_temp < 0 )
 		goto out;
 
-	printk("DS1775 digital thermometer detected at %02x\n", cl->addr );
+	printk("DS1775 digital thermometer [@%02x]\n", cl->addr );
 	print_temp("Temp: ", temp );
 	print_temp("  Hyst: ", hyst_temp );
 	print_temp("  OS: ", os_temp );
 	printk("\n");
 
-	if( x.thermostat ) {
-		x.error |= 1;
-		goto out;
-	}
 	x.temp = temp;
-	x.thermostat = cl;
 	x.overheat_temp = os_temp;
 	x.overheat_hyst = hyst_temp;
 	
 	cl->id = THERMOSTAT_CLIENT_ID;
-	strncpy( cl->name, "DS1775 thermostat", sizeof(cl->name) );
+	strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) );
 
-	if( i2c_attach_client( cl ) )
-		goto out;
-	return 0;
+	if( !i2c_attach_client(cl) )
+		x.thermostat = cl;
 out:
-	kfree( cl );
+	if( cl != x.thermostat )
+		kfree( cl );
 	return 0;
 }
 
 static int
-do_detect( struct i2c_adapter *adapter, int addr, int kind )
+do_probe( struct i2c_adapter *adapter, int addr, int kind )
 {
 	struct i2c_client *cl;
 
-	if( strncmp(adapter->name, "uni-n", 5) )
-		return 0;
 	if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA
 				     | I2C_FUNC_SMBUS_WRITE_BYTE) )
 		return 0;
 
-	if( !(cl=kmalloc( sizeof(struct i2c_client), GFP_KERNEL )) )
+	if( !(cl=kmalloc(sizeof(*cl), GFP_KERNEL)) )
 		return -ENOMEM;
 	memset( cl, 0, sizeof(struct i2c_client) );
 
@@ -349,108 +443,94 @@
 	cl->flags = 0;
 
 	if( addr < 0x48 )
-		return detect_fan( cl );
-	return detect_thermostat( cl );
+		return attach_fan( cl );
+	return attach_thermostat( cl );
+}
+
+
+/************************************************************************/
+/*	initialization / cleanup					*/
+/************************************************************************/
+
+static int
+therm_of_probe( struct of_device *dev, const struct of_match *match )
+{
+	return i2c_add_driver( &g4fan_driver );
 }
 
-#define PRINT_REG( r )	printk("reg %02x = %02x\n", r, read_reg(x.fan, r, 1) )
+static int
+therm_of_remove( struct of_device *dev )
+{
+	return i2c_del_driver( &g4fan_driver );
+}
+
+static struct of_match therm_of_match[] = {{
+	.name		= "fan",
+	.type		= OF_ANY_MATCH,
+	.compatible	= "adm1030"
+    }, {}
+};
+
+static struct of_platform_driver therm_of_driver = {
+	.name		= "temperature",
+	.match_table	= therm_of_match,
+	.probe		= therm_of_probe,
+	.remove		= therm_of_remove,
+};
+
+struct apple_thermal_info {
+	u8		id;			/* implementation ID */
+	u8		fan_count;		/* number of fans */
+	u8		thermostat_count;	/* number of thermostats */
+	u8		unused;
+};
 
 static int __init
 g4fan_init( void )
 {
 	struct apple_thermal_info *info;
 	struct device_node *np;
-	int ret, val;
-	
-	np = of_find_node_by_name(NULL, "power-mgt");
-	if (np == NULL)
+
+	init_MUTEX( &x.lock );
+
+	if( !(np=of_find_node_by_name(NULL, "power-mgt")) )
 		return -ENODEV;
 	info = (struct apple_thermal_info*)get_property(np, "thermal-info", NULL);
 	of_node_put(np);
-	if (info == NULL)
-		return -ENODEV;
-	
-	/* check for G4 "Windtunnel" SMP */
-	if( machine_is_compatible("PowerMac3,6") ) {
-		if( info->id != 3 ) {
-			printk(KERN_ERR "g4fan: design id %d unknown\n", info->id);
-			return -ENODEV;
-		}
-	} else {
-		printk(KERN_ERR "g4fan: unsupported machine type\n");
-		return -ENODEV;
-	}
-	if( (ret=i2c_add_driver(&g4fan_driver)) )
-		return ret;
 
-	if( !x.thermostat || !x.fan ) {
-		i2c_del_driver(&g4fan_driver );
+	if( !info || !machine_is_compatible("PowerMac3,6") )
 		return -ENODEV;
-	}
-
-	/* save registers (if we unload the module) */
-	x.r0 = read_reg( x.fan, 0x00, 1 );
-	x.r1 = read_reg( x.fan, 0x01, 1 );
-	x.r20 = read_reg( x.fan, 0x20, 1 );
-	x.r23 = read_reg( x.fan, 0x23, 1 );
-	x.r25 = read_reg( x.fan, 0x25, 1 );
 
-	/* improve measurement resolution (convergence time 1.5s) */
-	if( (val=read_reg( x.thermostat, 1, 1 )) >= 0 ) {
-		val |= 0x60;
-		if( write_reg( x.thermostat, 1, val, 1 ) )
-			printk("Failed writing config register\n");
+	if( info->id != 3 ) {
+		printk(KERN_ERR "therm_windtunnel: unsupported thermal design %d\n", info->id );
+		return -ENODEV;
 	}
-	/* disable interrupts and TAC input */
-	write_reg( x.fan, 0x01, 0x01, 1 );
-	/* enable filter */
-	write_reg( x.fan, 0x23, 0x91, 1 );
-	/* remote temp. controls fan */
-	write_reg( x.fan, 0x00, 0x95, 1 );
-
-	/* The thermostat (which besides measureing temperature controls
-	 * has a THERM output which puts the fan on 100%) is usually
-	 * set to kick in at 80 C (chip default). We reduce this a bit
-	 * to be on the safe side (OSX doesn't)...
-	 */
-	if( x.overheat_temp == (80 << 8) ) {
-		x.overheat_temp = 65 << 8;
-		x.overheat_hyst = 60 << 8;
-		write_reg( x.thermostat, 2, x.overheat_hyst, 2 );
-		write_reg( x.thermostat, 3, x.overheat_temp, 2 );
+	if( !(np=of_find_node_by_name(NULL, "fan")) )
+		return -ENODEV;
+	x.of_dev = of_platform_device_create( np, "temperature" );
+	of_node_put( np );
 
-		print_temp("Reducing overheating limit to ", x.overheat_temp );
-		print_temp(" (Hyst: ", x.overheat_hyst );
-		printk(")\n");
+	if( !x.of_dev ) {
+		printk(KERN_ERR "Can't register fan controller!\n");
+		return -ENODEV;
 	}
 
-	/* set an initial fan setting */
-	x.upind = x.downind = 1;
-	tune_fan( fan_up_table[x.upind].fan_setting );
-
-	INIT_WORK(&poll_work, poll_temp, NULL);
-
-	init_timer( &x.timer );
-	x.timer.expires = jiffies + 8*HZ;
-	x.timer.function = schedule_poll;
-	add_timer( &x.timer );
+	of_register_driver( &therm_of_driver );
 	return 0;
 }
 
 static void __exit
 g4fan_exit( void )
 {
-	del_timer( &x.timer );
+	of_unregister_driver( &therm_of_driver );
 
-	write_reg( x.fan, 0x01, x.r1, 1 );
-	write_reg( x.fan, 0x20, x.r20, 1 );
-	write_reg( x.fan, 0x23, x.r23, 1 );
-	write_reg( x.fan, 0x25, x.r25, 1 );
-	write_reg( x.fan, 0x00, x.r0, 1 );
-
-	i2c_del_driver( &g4fan_driver );
+	if( x.of_dev )
+		of_device_unregister( x.of_dev );
 }
 
 module_init(g4fan_init);
 module_exit(g4fan_exit);
 
+MODULE_AUTHOR("Samuel Rydh <samuel@ibrium.se>");
+MODULE_DESCRIPTION("Apple G4 (windtunnel) fan controller");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
--- a/drivers/macintosh/via-pmu.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/macintosh/via-pmu.c	Sat Apr  3 19:38:55 2004
@@ -137,7 +137,8 @@
 static int data_len;
 static volatile int adb_int_pending;
 static volatile int disable_poll;
-static struct adb_request bright_req_1, bright_req_2, bright_req_3;
+static struct adb_request bright_req_1, bright_req_2;
+static unsigned long async_req_locks;
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
 static int pmu_fully_inited = 0;
@@ -404,7 +405,6 @@
 
 	bright_req_1.complete = 1;
 	bright_req_2.complete = 1;
-	bright_req_3.complete = 1;
 #ifdef CONFIG_PMAC_PBOOK
 	batt_req.complete = 1;
 	if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
@@ -710,6 +710,8 @@
 	pmu_batteries[pmu_cur_battery].amperage = amperage;
 	pmu_batteries[pmu_cur_battery].voltage = voltage;
 	pmu_batteries[pmu_cur_battery].time_remaining = time;
+
+	clear_bit(0, &async_req_locks);
 }
 
 static void __pmac
@@ -785,12 +787,14 @@
 		pmu_batteries[pmu_cur_battery].time_remaining = 0;
 
 	pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count;
+
+	clear_bit(0, &async_req_locks);
 }
 
 static void __pmac
 query_battery_state(void)
 {
-	if (!batt_req.complete)
+	if (test_and_set_bit(0, &async_req_locks))
 		return;
 	if (pmu_kind == PMU_OHARE_BASED)
 		pmu_request(&batt_req, done_battery_state_ohare,
@@ -1690,20 +1694,30 @@
 	return 0;
 }
 
+static void __openfirmware
+pmu_bright_complete(struct adb_request *req)
+{
+	if (req == &bright_req_1)
+		clear_bit(1, &async_req_locks);
+	if (req == &bright_req_2)
+		clear_bit(2, &async_req_locks);
+}
+
 static int __openfirmware
 pmu_set_backlight_level(int level, void* data)
 {
 	if (vias == NULL)
 		return -ENODEV;
 
-	if (!bright_req_1.complete)
+	if (test_and_set_bit(1, &async_req_locks))
 		return -EAGAIN;
-	pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT,
+	pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT,
 		backlight_to_bright[level]);
-	if (!bright_req_2.complete)
+	if (test_and_set_bit(2, &async_req_locks))
 		return -EAGAIN;
-	pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT
-		| (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF));
+	pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
+		    PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
+					 PMU_POW_ON : PMU_POW_OFF));
 
 	return 0;
 }
@@ -2330,6 +2344,8 @@
 		return -EBUSY;
 	}
 	
+	preempt_disable();
+	
 	/* Make sure the decrementer won't interrupt us */
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
 	/* Make sure any pending DEC interrupt occurring while we did
@@ -2352,6 +2368,7 @@
 	if (ret) {
 		wakeup_decrementer();
 		local_irq_enable();
+		preempt_enable();
 		device_resume();
 		broadcast_wake();
 		printk(KERN_ERR "Driver powerdown failed\n");
@@ -2360,7 +2377,8 @@
 
 	/* Wait for completion of async backlight requests */
 	while (!bright_req_1.complete || !bright_req_2.complete ||
-		!bright_req_3.complete || !batt_req.complete)
+
+			!batt_req.complete)
 		pmu_poll();
 
 	/* Giveup the lazy FPU & vec so we don't have to back them
@@ -2398,6 +2416,8 @@
 
 	pmu_blink(1);
 
+	preempt_enable();
+
 	/* Resume devices */
 	device_resume();
 
@@ -2673,9 +2693,9 @@
 		mb();
 
 	pmac_wakeup_devices();
-
 	pbook_free_pci_save();
 	iounmap(mem_ctrl);
+
 	return 0;
 }
 
diff -Nru a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
--- a/drivers/mca/mca-bus.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/mca/mca-bus.c	Sat Apr  3 19:38:41 2004
@@ -106,6 +106,7 @@
 	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 -Nru a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
--- a/drivers/md/dm-crypt.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/md/dm-crypt.c	Sat Apr  3 19:38:40 2004
@@ -621,7 +621,8 @@
 	return clone;
 }
 
-static int crypt_map(struct dm_target *ti, struct bio *bio)
+static int crypt_map(struct dm_target *ti, struct bio *bio,
+		     union map_info *map_context)
 {
 	struct crypt_config *cc = (struct crypt_config *) ti->private;
 	struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO);
@@ -739,6 +740,7 @@
 
 static struct target_type crypt_target = {
 	.name   = "crypt",
+	.version= {1, 0, 0},
 	.module = THIS_MODULE,
 	.ctr    = crypt_ctr,
 	.dtr    = crypt_dtr,
diff -Nru a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
--- a/drivers/md/dm-ioctl.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/md/dm-ioctl.c	Sat Apr  3 19:38:42 2004
@@ -33,6 +33,14 @@
 	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 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 @@
 	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 @@
 	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 @@
 	/*
 	 * 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 @@
 	 */
 	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 @@
 		{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 @@
 	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 -Nru a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
--- a/drivers/md/dm-linear.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/md/dm-linear.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	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 struct target_type linear_target = {
 	.name   = "linear",
+	.version= {1, 0, 1},
 	.module = THIS_MODULE,
 	.ctr    = linear_ctr,
 	.dtr    = linear_dtr,
diff -Nru a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
--- a/drivers/md/dm-stripe.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/md/dm-stripe.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	/*
 	 * 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 @@
 	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 struct target_type stripe_target = {
 	.name   = "striped",
+	.version= {1, 0, 1},
 	.module = THIS_MODULE,
 	.ctr    = stripe_ctr,
 	.dtr    = stripe_dtr,
diff -Nru a/drivers/md/dm-table.c b/drivers/md/dm-table.c
--- a/drivers/md/dm-table.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/md/dm-table.c	Sat Apr  3 19:38:56 2004
@@ -329,13 +329,11 @@
  */
 static struct dm_dev *find_device(struct list_head *l, dev_t dev)
 {
-	struct list_head *tmp;
+	struct dm_dev *dd;
 
-	list_for_each(tmp, l) {
-		struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+	list_for_each_entry (dd, l, list)
 		if (dd->bdev->bd_dev == dev)
 			return dd;
-	}
 
 	return NULL;
 }
@@ -631,14 +629,20 @@
 	return 0;
 }
 
-static void set_default_limits(struct io_restrictions *rs)
+static void check_for_valid_limits(struct io_restrictions *rs)
 {
-	rs->max_sectors = MAX_SECTORS;
-	rs->max_phys_segments = MAX_PHYS_SEGMENTS;
-	rs->max_hw_segments = MAX_HW_SEGMENTS;
-	rs->hardsect_size = 1 << SECTOR_SHIFT;
-	rs->max_segment_size = MAX_SEGMENT_SIZE;
-	rs->seg_boundary_mask = -1;
+	if (!rs->max_sectors)
+		rs->max_sectors = MAX_SECTORS;
+	if (!rs->max_phys_segments)
+		rs->max_phys_segments = MAX_PHYS_SEGMENTS;
+	if (!rs->max_hw_segments)
+		rs->max_hw_segments = MAX_HW_SEGMENTS;
+	if (!rs->hardsect_size)
+		rs->hardsect_size = 1 << SECTOR_SHIFT;
+	if (!rs->max_segment_size)
+		rs->max_segment_size = MAX_SEGMENT_SIZE;
+	if (!rs->seg_boundary_mask)
+		rs->seg_boundary_mask = -1;
 }
 
 int dm_table_add_target(struct dm_table *t, const char *type,
@@ -653,7 +657,6 @@
 
 	tgt = t->targets + t->num_targets;
 	memset(tgt, 0, sizeof(*tgt));
-	set_default_limits(&tgt->limits);
 
 	if (!len) {
 		tgt->error = "zero-length target";
@@ -737,6 +740,8 @@
 {
 	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);
diff -Nru a/drivers/md/dm-target.c b/drivers/md/dm-target.c
--- a/drivers/md/dm-target.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/md/dm-target.c	Sat Apr  3 19:38:56 2004
@@ -25,15 +25,11 @@
 
 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 @@
 	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 @@
 	/* 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 -Nru a/drivers/md/dm.c b/drivers/md/dm.c
--- a/drivers/md/dm.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/md/dm.c	Sat Apr  3 19:38:54 2004
@@ -21,6 +21,9 @@
 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 @@
 };
 
 /*
+ * 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
@@ -59,6 +72,7 @@
 	 * io objects are allocated from here.
 	 */
 	mempool_t *io_pool;
+	mempool_t *tio_pool;
 
 	/*
 	 * Event handling.
@@ -69,6 +83,7 @@
 
 #define MIN_IOS 256
 static kmem_cache_t *_io_cache;
+static kmem_cache_t *_tio_cache;
 
 static __init int local_init(void)
 {
@@ -80,9 +95,18 @@
 	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 +119,7 @@
 
 static void local_exit(void)
 {
+	kmem_cache_destroy(_tio_cache);
 	kmem_cache_destroy(_io_cache);
 
 	if (unregister_blkdev(_major, _name) < 0)
@@ -184,6 +209,16 @@
 	mempool_free(io, md->io_pool);
 }
 
+static inline struct target_io *alloc_tio(struct mapped_device *md)
+{
+	return mempool_alloc(md->tio_pool, GFP_NOIO);
+}
+
+static inline void free_tio(struct mapped_device *md, struct target_io *tio)
+{
+	mempool_free(tio, md->tio_pool);
+}
+
 /*
  * Add the bio to the list of deferred io.
  */
@@ -232,17 +267,30 @@
 
 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 +311,8 @@
 	return len;
 }
 
-static void __map_bio(struct dm_target *ti, struct bio *clone, struct dm_io *io)
+static void __map_bio(struct dm_target *ti, struct bio *clone,
+		      struct target_io *tio)
 {
 	int r;
 
@@ -273,22 +322,25 @@
 	BUG_ON(!clone->bi_size);
 
 	clone->bi_end_io = clone_endio;
-	clone->bi_private = io;
+	clone->bi_private = tio;
 
 	/*
 	 * Map the clone.  If r == 0 we don't need to do
 	 * anything, the target has assumed ownership of
 	 * this io.
 	 */
-	atomic_inc(&io->io_count);
-	r = ti->type->map(ti, clone);
+	atomic_inc(&tio->io->io_count);
+	r = ti->type->map(ti, clone, &tio->info);
 	if (r > 0)
 		/* the bio has been remapped so dispatch it */
 		generic_make_request(clone);
 
-	else if (r < 0)
+	else if (r < 0) {
 		/* error the io and bail out */
+		struct dm_io *io = tio->io;
+		free_tio(tio->io->md, tio);
 		dec_pending(io, -EIO);
+	}
 }
 
 struct clone_info {
@@ -348,6 +400,15 @@
 	struct bio *clone, *bio = ci->bio;
 	struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector);
 	sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti);
+	struct target_io *tio;
+
+	/*
+	 * Allocate a target io object.
+	 */
+	tio = alloc_tio(ci->md);
+	tio->io = ci->io;
+	tio->ti = ti;
+	memset(&tio->info, 0, sizeof(tio->info));
 
 	if (ci->sector_count <= max) {
 		/*
@@ -356,7 +417,7 @@
 		 */
 		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 +440,7 @@
 		}
 
 		clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len);
-		__map_bio(ti, clone, ci->io);
+		__map_bio(ti, clone, tio);
 
 		ci->sector += len;
 		ci->sector_count -= len;
@@ -394,7 +455,7 @@
 
 		clone = split_bvec(bio, ci->sector, ci->idx,
 				   bv->bv_offset, max);
-		__map_bio(ti, clone, ci->io);
+		__map_bio(ti, clone, tio);
 
 		ci->sector += max;
 		ci->sector_count -= max;
@@ -403,7 +464,11 @@
 		len = to_sector(bv->bv_len) - max;
 		clone = split_bvec(bio, ci->sector, ci->idx,
 				   bv->bv_offset + to_bytes(max), len);
-		__map_bio(ti, clone, ci->io);
+		tio = alloc_tio(ci->md);
+		tio->io = ci->io;
+		tio->ti = ti;
+		memset(&tio->info, 0, sizeof(tio->info));
+		__map_bio(ti, clone, tio);
 
 		ci->sector += len;
 		ci->sector_count -= len;
@@ -441,6 +506,16 @@
  *---------------------------------------------------------------*/
 
 
+static inline void __dm_request(struct mapped_device *md, struct bio *bio)
+{
+	if (!md->map) {
+		bio_io_error(bio, bio->bi_size);
+		return;
+	}
+
+	__split_bio(md, bio);
+}
+
 /*
  * The request function that just remaps the bio built up by
  * dm_merge_bvec.
@@ -479,12 +554,7 @@
 		down_read(&md->lock);
 	}
 
-	if (!md->map) {
-		bio_io_error(bio, bio->bi_size);
-		return 0;
-	}
-
-	__split_bio(md, bio);
+	__dm_request(md, bio);
 	up_read(&md->lock);
 	return 0;
 }
@@ -574,9 +644,14 @@
  	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 +667,8 @@
 
 	return md;
 
-
+ bad4:
+	mempool_destroy(md->tio_pool);
  bad3:
 	mempool_destroy(md->io_pool);
  bad2:
@@ -606,6 +682,7 @@
 static void free_dev(struct mapped_device *md)
 {
 	free_minor(md->disk->first_minor);
+	mempool_destroy(md->tio_pool);
 	mempool_destroy(md->io_pool);
 	del_gendisk(md->disk);
 	put_disk(md->disk);
@@ -644,13 +721,13 @@
 {
 	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;
 
+	md->map = t;
 	dm_table_event_callback(md->map, event_callback, md);
 
 	dm_table_get(t);
@@ -710,16 +787,16 @@
 }
 
 /*
- * Requeue the deferred bios by calling generic_make_request.
+ * Process the deferred bios
  */
-static void flush_deferred_io(struct bio *c)
+static void __flush_deferred_io(struct mapped_device *md, struct bio *c)
 {
 	struct bio *n;
 
 	while (c) {
 		n = c->bi_next;
 		c->bi_next = NULL;
-		generic_make_request(c);
+		__dm_request(md, c);
 		c = n;
 	}
 }
@@ -814,10 +891,11 @@
 	dm_table_resume_targets(md->map);
 	clear_bit(DMF_SUSPENDED, &md->flags);
 	clear_bit(DMF_BLOCK_IO, &md->flags);
+
 	def = bio_list_get(&md->deferred);
+	__flush_deferred_io(md, def);
 	up_write(&md->lock);
 
-	flush_deferred_io(def);
 	blk_run_queues();
 
 	return 0;
diff -Nru a/drivers/md/dm.h b/drivers/md/dm.h
--- a/drivers/md/dm.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/md/dm.h	Sat Apr  3 19:38:43 2004
@@ -123,6 +123,8 @@
 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 -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/md/md.c	Sat Apr  3 19:38:42 2004
@@ -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];
@@ -1447,7 +1447,7 @@
 	return 1;
 }
 
-static int mdp_major = 0;
+int mdp_major = 0;
 
 static struct kobject *md_probe(dev_t dev, int *part, void *data)
 {
@@ -1792,7 +1792,7 @@
  *
  * If "unit" is allocated, then bump its reference count
  */
-static void autorun_devices(void)
+static void autorun_devices(int part)
 {
 	struct list_head candidates;
 	struct list_head *tmp;
@@ -1825,7 +1825,12 @@
 			       bdevname(rdev0->bdev, b), rdev0->preferred_minor);
 			break;
 		}
-		dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
+		if (part)
+			dev = MKDEV(mdp_major,
+				    rdev0->preferred_minor << MdpMinorShift);
+		else
+			dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
+
 		md_probe(dev, NULL, NULL);
 		mddev = mddev_find(dev);
 		if (!mddev) {
@@ -1922,7 +1927,7 @@
 	/*
 	 * possibly return codes
 	 */
-	autorun_devices();
+	autorun_devices(0);
 	return 0;
 
 }
@@ -2407,7 +2412,7 @@
 #ifndef MODULE
 		case RAID_AUTORUN:
 			err = 0;
-			autostart_arrays();
+			autostart_arrays(arg);
 			goto done;
 #endif
 		default:;
@@ -3173,13 +3178,14 @@
 static void md_do_sync(mddev_t *mddev)
 {
 	mddev_t *mddev2;
-	unsigned int max_sectors, currspeed = 0,
-		j, window;
+	unsigned int currspeed = 0,
+		 window;
+	sector_t max_sectors,j;
 	unsigned long mark[SYNC_MARKS];
-	unsigned long mark_cnt[SYNC_MARKS];
+	sector_t mark_cnt[SYNC_MARKS];
 	int last_mark,m;
 	struct list_head *tmp;
-	unsigned long last_check;
+	sector_t last_check;
 
 	/* just incase thread restarts... */
 	if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
@@ -3248,8 +3254,8 @@
 	 * Tune reconstruction:
 	 */
 	window = 32*(PAGE_SIZE/512);
-	printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n",
-		window/2,max_sectors/2);
+	printk(KERN_INFO "md: using %dk window, over a total of %Lu blocks.\n",
+		window/2,(unsigned long long) max_sectors/2);
 
 	atomic_set(&mddev->recovery_active, 0);
 	init_waitqueue_head(&mddev->recovery_wait);
@@ -3317,7 +3323,7 @@
 		 */
 		cond_resched();
 
-		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
+		currspeed = ((unsigned long)(j-mddev->resync_mark_cnt))/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
 
 		if (currspeed > sysctl_speed_limit_min) {
 			if ((currspeed > sysctl_speed_limit_max) ||
@@ -3577,7 +3583,7 @@
 }
 
 
-static void autostart_arrays(void)
+static void autostart_arrays(int part)
 {
 	char b[BDEVNAME_SIZE];
 	mdk_rdev_t *rdev;
@@ -3602,7 +3608,7 @@
 	}
 	dev_cnt = 0;
 
-	autorun_devices();
+	autorun_devices(part);
 }
 
 #endif
diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c
--- a/drivers/md/raid0.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/md/raid0.c	Sat Apr  3 19:38:43 2004
@@ -313,8 +313,8 @@
 
 	/* 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 @@
 	 */
 	{
 		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 -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/md/raid5.c	Sat Apr  3 19:38:41 2004
@@ -181,7 +181,7 @@
 
 static void raid5_build_block (struct stripe_head *sh, int i);
 
-static inline void init_stripe(struct stripe_head *sh, unsigned long sector, int pd_idx)
+static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
 {
 	raid5_conf_t *conf = sh->raid_conf;
 	int disks = conf->raid_disks, i;
@@ -218,25 +218,25 @@
 	insert_hash(conf, sh);
 }
 
-static struct stripe_head *__find_stripe(raid5_conf_t *conf, unsigned long sector)
+static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector)
 {
 	struct stripe_head *sh;
 
 	CHECK_DEVLOCK();
-	PRINTK("__find_stripe, sector %lu\n", sector);
+	PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector);
 	for (sh = stripe_hash(conf, sector); sh; sh = sh->hash_next)
 		if (sh->sector == sector)
 			return sh;
-	PRINTK("__stripe %lu not in cache\n", sector);
+	PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector);
 	return NULL;
 }
 
-static struct stripe_head *get_active_stripe(raid5_conf_t *conf, unsigned long sector, 
+static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector,
 					     int pd_idx, int noblock) 
 {
 	struct stripe_head *sh;
 
-	PRINTK("get_stripe, sector %lu\n", sector);
+	PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector);
 
 	spin_lock_irq(&conf->device_lock);
 
@@ -495,7 +495,7 @@
  * Input: a 'big' sector number,
  * Output: index of the data and parity disk, and the sector # in them.
  */
-static unsigned long raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
+static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
 			unsigned int data_disks, unsigned int * dd_idx,
 			unsigned int * pd_idx, raid5_conf_t *conf)
 {
@@ -556,7 +556,7 @@
 	/*
 	 * Finally, compute the new sector number
 	 */
-	new_sector = stripe * sectors_per_chunk + chunk_offset;
+	new_sector = (sector_t)stripe * sectors_per_chunk + chunk_offset;
 	return new_sector;
 }
 
@@ -567,7 +567,7 @@
 	int raid_disks = conf->raid_disks, data_disks = raid_disks - 1;
 	sector_t new_sector = sh->sector, check;
 	int sectors_per_chunk = conf->chunk_size >> 9;
-	long stripe;
+	sector_t stripe;
 	int chunk_offset;
 	int chunk_number, dummy1, dummy2, dd_idx = i;
 	sector_t r_sector;
@@ -1388,7 +1388,7 @@
 	unsigned long stripe;
 	int chunk_offset;
 	int dd_idx, pd_idx;
-	unsigned long first_sector;
+	sector_t first_sector;
 	int raid_disks = conf->raid_disks;
 	int data_disks = raid_disks-1;
 
@@ -1401,7 +1401,7 @@
 	stripe = x;
 	BUG_ON(x != stripe);
 
-	first_sector = raid5_compute_sector(stripe*data_disks*sectors_per_chunk
+	first_sector = raid5_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk
 		+ chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf);
 	sh = get_active_stripe(conf, sector_nr, pd_idx, 1);
 	if (sh == NULL) {
@@ -1409,7 +1409,8 @@
 		/* 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 @@
 
 	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 -Nru a/drivers/md/raid6main.c b/drivers/md/raid6main.c
--- a/drivers/md/raid6main.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/md/raid6main.c	Sat Apr  3 19:38:40 2004
@@ -200,7 +200,7 @@
 
 static void raid6_build_block (struct stripe_head *sh, int i);
 
-static inline void init_stripe(struct stripe_head *sh, unsigned long sector, int pd_idx)
+static inline void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
 {
 	raid6_conf_t *conf = sh->raid_conf;
 	int disks = conf->raid_disks, i;
@@ -237,25 +237,25 @@
 	insert_hash(conf, sh);
 }
 
-static struct stripe_head *__find_stripe(raid6_conf_t *conf, unsigned long sector)
+static struct stripe_head *__find_stripe(raid6_conf_t *conf, sector_t sector)
 {
 	struct stripe_head *sh;
 
 	CHECK_DEVLOCK();
-	PRINTK("__find_stripe, sector %lu\n", sector);
+	PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector);
 	for (sh = stripe_hash(conf, sector); sh; sh = sh->hash_next)
 		if (sh->sector == sector)
 			return sh;
-	PRINTK("__stripe %lu not in cache\n", sector);
+	PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector);
 	return NULL;
 }
 
-static struct stripe_head *get_active_stripe(raid6_conf_t *conf, unsigned long sector,
+static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector,
 					     int pd_idx, int noblock)
 {
 	struct stripe_head *sh;
 
-	PRINTK("get_stripe, sector %lu\n", sector);
+	PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector);
 
 	spin_lock_irq(&conf->device_lock);
 
@@ -516,7 +516,7 @@
  * Input: a 'big' sector number,
  * Output: index of the data and parity disk, and the sector # in them.
  */
-static unsigned long raid6_compute_sector(sector_t r_sector, unsigned int raid_disks,
+static sector_t raid6_compute_sector(sector_t r_sector, unsigned int raid_disks,
 			unsigned int data_disks, unsigned int * dd_idx,
 			unsigned int * pd_idx, raid6_conf_t *conf)
 {
@@ -588,7 +588,7 @@
 	/*
 	 * Finally, compute the new sector number
 	 */
-	new_sector = stripe * sectors_per_chunk + chunk_offset;
+	new_sector = (sector_t) stripe * sectors_per_chunk + chunk_offset;
 	return new_sector;
 }
 
@@ -599,7 +599,7 @@
 	int raid_disks = conf->raid_disks, data_disks = raid_disks - 2;
 	sector_t new_sector = sh->sector, check;
 	int sectors_per_chunk = conf->chunk_size >> 9;
-	long stripe;
+	sector_t stripe;
 	int chunk_offset;
 	int chunk_number, dummy1, dummy2, dd_idx = i;
 	sector_t r_sector;
@@ -1550,7 +1550,7 @@
 	unsigned long stripe;
 	int chunk_offset;
 	int dd_idx, pd_idx;
-	unsigned long first_sector;
+	sector_t first_sector;
 	int raid_disks = conf->raid_disks;
 	int data_disks = raid_disks - 2;
 
@@ -1563,7 +1563,7 @@
 	stripe = x;
 	BUG_ON(x != stripe);
 
-	first_sector = raid6_compute_sector(stripe*data_disks*sectors_per_chunk
+	first_sector = raid6_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk
 		+ chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf);
 	sh = get_active_stripe(conf, sector_nr, pd_idx, 1);
 	if (sh == NULL) {
@@ -1571,7 +1571,8 @@
 		/* 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 +1772,14 @@
 
 	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 -Nru a/drivers/media/dvb/frontends/alps_tdlb7.c b/drivers/media/dvb/frontends/alps_tdlb7.c
--- a/drivers/media/dvb/frontends/alps_tdlb7.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/media/dvb/frontends/alps_tdlb7.c	Sat Apr  3 19:38:42 2004
@@ -29,8 +29,6 @@
 */  
 
 
-
-#define __KERNEL_SYSCALLS__
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/vmalloc.h>
@@ -58,8 +56,6 @@
 #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 @@
 	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 @@
 		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 -Nru a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
--- a/drivers/media/dvb/frontends/sp887x.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/media/dvb/frontends/sp887x.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 		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 @@
 
 	// 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 @@
 	// 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 -Nru a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
--- a/drivers/media/dvb/frontends/tda1004x.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/media/dvb/frontends/tda1004x.c	Sat Apr  3 19:38:40 2004
@@ -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 @@
 
 	// 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 @@
 	}
 
 	// 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 -Nru a/drivers/media/video/meye.c b/drivers/media/video/meye.c
--- a/drivers/media/video/meye.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/media/video/meye.c	Sat Apr  3 19:38:44 2004
@@ -160,13 +160,15 @@
 	}
 }
 
-/* return a page table pointing to N pages of locked memory
+/*
+ * return a page table pointing to N pages of locked memory
  *
  * NOTE: The meye device expects dma_addr_t size to be 32 bits
  * (the toc must be exactly 1024 entries each of them being 4 bytes
  * in size, the whole result being 4096 bytes). We're using here
- * dma_addr_t for corectness but the compilation of this driver is
- * disabled for HIGHMEM64G=y, where sizeof(dma_addr_t) != 4 */
+ * dma_addr_t for correctness but the compilation of this driver is
+ * disabled for HIGHMEM64G=y, where sizeof(dma_addr_t) != 4
+ */
 static int ptable_alloc(void) {
 	dma_addr_t *pt;
 	int i;
diff -Nru a/drivers/media/video/meye.h b/drivers/media/video/meye.h
--- a/drivers/media/video/meye.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/media/video/meye.h	Sat Apr  3 19:38:43 2004
@@ -31,7 +31,7 @@
 #define _MEYE_PRIV_H_
 
 #define MEYE_DRIVER_MAJORVERSION	1
-#define MEYE_DRIVER_MINORVERSION	8
+#define MEYE_DRIVER_MINORVERSION	9
 
 #include <linux/config.h>
 #include <linux/types.h>
diff -Nru a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
--- a/drivers/media/video/video-buf.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/media/video/video-buf.c	Sat Apr  3 19:38:43 2004
@@ -215,7 +215,7 @@
 		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 -Nru a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
--- a/drivers/media/video/zoran_driver.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/media/video/zoran_driver.c	Sat Apr  3 19:38:54 2004
@@ -2815,7 +2815,7 @@
 				     fh->jpg_settings.TmpDcm);
 				fmt->fmt.pix.sizeimage =
 				    zoran_v4l2_calc_bufsize(&fh->
-							    jpg_settings);;
+							    jpg_settings);
 				fmt->fmt.pix.pixelformat =
 				    V4L2_PIX_FMT_MJPEG;
 				if (fh->jpg_settings.TmpDcm == 1)
diff -Nru a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
--- a/drivers/message/fusion/Kconfig	Sat Apr  3 19:38:57 2004
+++ b/drivers/message/fusion/Kconfig	Sat Apr  3 19:38:57 2004
@@ -3,7 +3,7 @@
 
 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 @@
 
 	  [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 @@
 	  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 @@
 
 	  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 -Nru a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
--- a/drivers/message/fusion/Makefile	Sat Apr  3 19:38:45 2004
+++ b/drivers/message/fusion/Makefile	Sat Apr  3 19:38:45 2004
@@ -17,10 +17,16 @@
 
 # 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 -Nru a/drivers/message/fusion/isense.c b/drivers/message/fusion/isense.c
--- a/drivers/message/fusion/isense.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/message/fusion/isense.c	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
--- a/drivers/message/fusion/linux_compat.h	Sat Apr  3 19:38:42 2004
+++ b/drivers/message/fusion/linux_compat.h	Sat Apr  3 19:38:42 2004
@@ -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 @@
 
 
 /* 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 @@
 /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 #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 -Nru a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
--- a/drivers/message/fusion/lsi/mpi.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/message/fusion/lsi/mpi.h	Sat Apr  3 19:38:41 2004
@@ -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 @@
 /*  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 @@
 
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 /****************************************************************************/
 
 #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 -Nru a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
--- a/drivers/message/fusion/lsi/mpi_cnfg.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h	Sat Apr  3 19:38:43 2004
@@ -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 @@
 } 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 @@
 #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 @@
 #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 @@
     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 @@
     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 @@
 /****************************************************************************
 *   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 @@
     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 @@
 } 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 @@
 } 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 @@
 #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 @@
 
 #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 _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 @@
 #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 @@
 #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 @@
 #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 @@
     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 @@
 } 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 @@
 #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 @@
 #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 @@
 #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 @@
 
 #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 @@
 #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 @@
     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 @@
 #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 @@
 
 #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 @@
 } 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 @@
     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 @@
 } 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 @@
 #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
@@ -1564,6 +1788,318 @@
 
 #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 -Nru a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h
--- a/drivers/message/fusion/lsi/mpi_fc.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/message/fusion/lsi/mpi_fc.h	Sat Apr  3 19:38:41 2004
@@ -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 @@
   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 -Nru a/drivers/message/fusion/lsi/mpi_inb.h b/drivers/message/fusion/lsi/mpi_inb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/message/fusion/lsi/mpi_inb.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
--- a/drivers/message/fusion/lsi/mpi_init.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/message/fusion/lsi/mpi_init.h	Sat Apr  3 19:38:41 2004
@@ -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 @@
 #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 @@
 #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 @@
 
 
 /****************************************************************************/
+/*  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 @@
 #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 -Nru a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
--- a/drivers/message/fusion/lsi/mpi_ioc.h	Sat Apr  3 19:38:42 2004
+++ b/drivers/message/fusion/lsi/mpi_ioc.h	Sat Apr  3 19:38:42 2004
@@ -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 @@
     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 @@
     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 @@
 
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 -Nru a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h
--- a/drivers/message/fusion/lsi/mpi_lan.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/message/fusion/lsi/mpi_lan.h	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h
--- a/drivers/message/fusion/lsi/mpi_raid.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/message/fusion/lsi/mpi_raid.h	Sat Apr  3 19:38:43 2004
@@ -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 @@
 #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 @@
 
 
 /****************************************************************************/
-/* Mailbox request structure */
+/* Mailbox reqeust structure */
 /****************************************************************************/
 
 typedef struct _MSG_MAILBOX_REQUEST
@@ -195,6 +201,7 @@
     U16                     Reserved2;
     U8                      Reserved3;
     U8                      MsgFlags;
+    U32                     MsgContext;
     U8                      Command[10];
     U16                     Reserved4;
     SGE_IO_UNION            SGL;
diff -Nru a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/message/fusion/lsi/mpi_sas.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h
--- a/drivers/message/fusion/lsi/mpi_targ.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/message/fusion/lsi/mpi_targ.h	Sat Apr  3 19:38:41 2004
@@ -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 @@
     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 @@
     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 -Nru a/drivers/message/fusion/lsi/mpi_tool.h b/drivers/message/fusion/lsi/mpi_tool.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/message/fusion/lsi/mpi_tool.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h
--- a/drivers/message/fusion/lsi/mpi_type.h	Sat Apr  3 19:38:44 2004
+++ b/drivers/message/fusion/lsi/mpi_type.h	Sat Apr  3 19:38:44 2004
@@ -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 -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
--- a/drivers/message/fusion/mptbase.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/message/fusion/mptbase.c	Sat Apr  3 19:38:42 2004
@@ -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	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_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 @@
 			return IRQ_NONE;
 		}
 	}
+#endif
 
 	/*
 	 *  Drain the reply FIFO!
@@ -521,17 +522,7 @@
 			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 @@
 	} 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 @@
 			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 @@
 		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_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 @@
 		iocp->mfcnt++;
 #endif
 	}
+	else
+		mf = NULL;
 	spin_unlock_irqrestore(&iocp->FreeQlock, flags);
 
 #ifdef MFCNT
@@ -986,7 +972,11 @@
 
 		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 @@
 				 ((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 @@
 
 		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 @@
 				(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_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 *
 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 @@
 	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"));
@@ -1284,24 +1280,47 @@
 		return r;
 	}
 
+#if 0
+	/* broken because some code assumes that multiple calls
+	   to pci_alloc_consistent return data in the same 4GB segment. 
+	   This cannot work on machines with enough memory. */
 	if (!pci_set_consistent_dma_mask(pdev, mask))
 		dprintk((KERN_INFO MYNAM
 			": Using 64 bit consistent mask\n"));
 	else
 		dprintk((KERN_INFO MYNAM
 			": Not using 64 bit consistent mask\n"));
+#endif
 
 	ioc = kmalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
 	if (ioc == NULL) {
 		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 +1431,45 @@
 	}
 	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 +1531,18 @@
 			|| (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 +1582,7 @@
 	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 +1592,6 @@
 	Q_DEL_ITEM(ioc);
 	mpt_adapter_dispose(ioc);
 
-	mptscsih_sync_irq(pdev->irq);
 	pci_set_drvdata(pdev, NULL);
 }
 
@@ -1755,20 +1772,23 @@
 	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 +1796,29 @@
 		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 +1827,55 @@
 					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 +1887,14 @@
 			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 +1907,13 @@
 		}
 	}
 
+	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 +1925,7 @@
 	 *  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 +1939,7 @@
 	 *	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 +1981,8 @@
 			/* Check, and possibly reset, the coalescing value
 			 */
 			mpt_read_ioc_pg_1(ioc);
+
+			mpt_read_ioc_pg_4(ioc);
 		}
 
 		GetIoUnitPage2(ioc);
@@ -1942,24 +1997,24 @@
 	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 +2169,15 @@
 			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 +2493,7 @@
 	 * 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 +2574,7 @@
 			 */
 			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 +2642,7 @@
 	 * 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 +2715,8 @@
 /*	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 +2729,9 @@
 		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 +2842,8 @@
 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 +2991,7 @@
 	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 +3123,16 @@
 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 +3166,11 @@
 		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 +3420,7 @@
 		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 +3621,11 @@
 		} 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 +3743,7 @@
 	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 +3806,11 @@
 
 	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 +3852,11 @@
 		 */
 		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 +3972,8 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
- *	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 +4033,7 @@
 	 * 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 +4051,7 @@
 				    (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 +4215,7 @@
 	} 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 +4232,7 @@
 	 * 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 +4241,7 @@
 		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 +4544,7 @@
 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 +4606,9 @@
 				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 +4633,6 @@
 			}
 			if (pbuf) {
 				pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
-				pbuf = NULL;
 			}
 		}
 	}
@@ -4589,6 +4669,8 @@
 				/* 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 +4680,6 @@
 			}
 
 			pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma);
-			pbuf = NULL;
 		}
 	}
 
@@ -4671,11 +4752,12 @@
  *	-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 +4767,6 @@
 	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 +4795,22 @@
 	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 +4835,14 @@
 	/* 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 +4850,7 @@
 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 +4903,66 @@
 		}
 	}
 
-	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 +5038,7 @@
 		}
 	}
 
-	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 +5154,8 @@
 	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 +5214,112 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/**
+ *	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 +5361,12 @@
 
 	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 +5830,7 @@
 	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 +5851,29 @@
 	/* 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 +5888,7 @@
 		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 +5897,7 @@
 static char *
 EventDescriptionStr(u8 event, u32 evData0)
 {
-	char *ds = NULL;
+	char *ds;
 
 	switch(event) {
 	case MPI_EVENT_NONE:
@@ -5839,109 +6102,11 @@
 		"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 +6186,6 @@
 		isense_idx = last_drv_idx;
 		r = 1;
 	}
-	mpt_inc_use_count();
 	return r;
 }
 
@@ -6040,7 +6204,6 @@
 	mpt_ScsiOpcodesPtr = NULL;
 	printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n");
 	isense_idx = -1;
-	mpt_dec_use_count();
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -6072,6 +6235,8 @@
 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 -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
--- a/drivers/message/fusion/mptbase.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/message/fusion/mptbase.h	Sat Apr  3 19:38:41 2004
@@ -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 @@
 	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 @@
 		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 @@
 		MPIHeader_t		hdr;
 		SCSIIORequest_t		scsireq;
 		SCSIIOReply_t		sreply;
+		ConfigReply_t		configreply;
 		MPIDefaultReply_t	reply;
 		MPT_FRAME_TRACKER	frame;
 	} u;
@@ -408,12 +412,9 @@
 	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 @@
 	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 @@
 /* #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 @@
 	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 @@
 	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 @@
 	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 @@
 /* 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 @@
 #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 @@
 	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 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 -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
--- a/drivers/message/fusion/mptctl.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/message/fusion/mptctl.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 			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 @@
 	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 @@
 		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 @@
 		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 @@
 {
 	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 @@
 		}
 
 	} 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 @@
 		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 @@
 		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 @@
 	/* 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 @@
 
 	/* 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 @@
 	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 @@
 		 * 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 @@
 #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 @@
 	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 @@
 	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 @@
 	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 @@
 			 */
 			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 @@
 			/* 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 @@
 			 */
 			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 @@
 			/* 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 @@
 					__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 @@
 	 * 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 @@
 	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 @@
 				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 @@
 					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 @@
 			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 @@
 				/* 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 @@
 
 	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 @@
 			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 @@
 	}
 
 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 @@
 	 */
 	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 @@
 	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 @@
 				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 @@
 		}
 	}
 
+	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 @@
  * 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 @@
 	}
 
 #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 -Nru a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
--- a/drivers/message/fusion/mptctl.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/message/fusion/mptctl.h	Sat Apr  3 19:38:43 2004
@@ -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 @@
 #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 @@
 /*
  *  Header:
  *  iocnum 	required (input)
- *  host 	ignored	
+ *  host 	ignored
  *  channe	ignored
  *  id		ignored
  *  lun		ignored
@@ -371,9 +372,9 @@
 	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 @@
 	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 -Nru a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
--- a/drivers/message/fusion/mptlan.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/message/fusion/mptlan.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 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 @@
 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_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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 			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 @@
 //					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 @@
 			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 @@
 
 	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 -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
--- a/drivers/message/fusion/mptscsih.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/message/fusion/mptscsih.c	Sat Apr  3 19:38:57 2004
@@ -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 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 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  __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	mpt_scsi_hosts = 0;
-static atomic_t	queue_depth;
 
 static int	ScsiDoneCtx = -1;
 static int	ScsiTaskCtx = -1;
@@ -243,6 +244,10 @@
 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 @@
 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 @@
 		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 @@
 	/* 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 @@
 
 	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 @@
 		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 @@
 		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 @@
 
 	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 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 @@
 
 		/* Do the OS callback.
 		 */
-                MPT_HOST_LOCK(flags);
 		SCpnt->scsi_done(SCpnt);
-                MPT_HOST_UNLOCK(flags);
 	}
 
 	return;
@@ -1055,6 +1061,26 @@
 	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 @@
 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 @@
 			}
 			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 @@
 	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 @@
 			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 @@
 	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 @@
 	/* 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 @@
 	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 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 @@
  *
  *
  */
-static void __devexit
+static void
 mptscsih_remove(struct pci_dev *pdev)
 {
 	MPT_ADAPTER 		*ioc = pci_get_drvdata(pdev);
@@ -1920,7 +1923,7 @@
 
 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 @@
 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 @@
 	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 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 @@
 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 @@
 
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-	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 @@
 	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 @@
 
 	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 @@
 
 	/* 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 @@
 
 	/*
 	 *  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 @@
 		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 @@
 			}
 		}
 
+#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 @@
 	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 @@
 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 @@
  *	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 @@
 		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 @@
 	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 @@
 #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 @@
 		 */
 		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 @@
  *	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 @@
 	 */
 	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 @@
 		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 @@
 		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 @@
 
 	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 @@
 		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;
 
-	/* Unsupported for SCSI. Suppored for FCP
+	printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n",
+	       hd->ioc->name, SCpnt);
+
+	/* 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 @@
 		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 @@
 
 	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 @@
 {
 	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 @@
 			 */
 			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 @@
 			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 @@
 
 	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 @@
 	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 @@
 	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,21 +3366,33 @@
 			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->is_spi) 
+				return;
 
-				if (hd->negoNvram == 0)
-					hd->ioc->spi_data.dvStatus[device->id] |= MPT_SCSICFG_DV_NOT_DONE;
+			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;
+					}
+			}
 
-				/* 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;
+			if(!raid_volume){
+				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;
 			}
 		}
 	}
-
+	
 	return;
 }
 
@@ -3525,205 +3405,76 @@
 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 (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));
-			}
-
-			mptscsih_target_settings(hd, vdev, device);
+	struct Scsi_Host	*sh = device->host;
+	VirtDevice		*pTarget;
+	MPT_SCSI_HOST		*hd = (MPT_SCSI_HOST *)sh->hostdata;
 
-			vdev->tflags |= MPT_TARGET_FLAGS_CONFIGURED;
-		}
+	if ((hd == NULL) || (hd->Targets == NULL)) {
+		return 0;
+	}
 
-		if (vdev) {
-			/* set the queue depth for all devices
-			 */
-			if (!device->tagged_supported ||
-			    !(vdev->tflags & MPT_TARGET_FLAGS_Q_YES)) {
+	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 (vdev->type == 0x00
-				   && (vdev->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) {
+			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 {
+					MPT_SCSI_CMD_PER_DEV_HIGH);
+			else
 				scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
-							MPT_SCSI_CMD_PER_DEV_LOW);
-			}
-
-			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;
-
+					MPT_SCSI_CMD_PER_DEV_LOW);
 		} else {
-			factor = MPT_ASYNC;
-			offset = 0;
+			/* error case - No Inq. Data */
+			scsi_adjust_queue_depth(device, 0, 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 (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;
+	dsprintk((MYIOC_s_INFO_FMT
+		"Queue depth=%d, tflags=%x\n",
+		hd->ioc->name, device->queue_depth, pTarget->tflags));
 
-	if (noQas)
-		target->negoFlags |= MPT_TARGET_NO_NEGO_QAS;
+	dsprintk((MYIOC_s_INFO_FMT
+		"negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
+		hd->ioc->name, pTarget->negoFlags, pTarget->maxOffset, pTarget->minSyncFactor));
 
-	/* 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;
-	}
+slave_configure_exit:
 
-	/* Disable QAS if mixed configuration case
-	 */
-	if ((noQas) && (!pspi_data->noQas) && (target->type == 0x00)){
-		VirtDevice	*vdev;
-		int ii;
+	dsprintk((MYIOC_s_INFO_FMT
+		"tagged %d, simple %d, ordered %d\n",
+		hd->ioc->name,device->tagged_supported, device->simple_tags,
+		device->ordered_tags));
 
-		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;
-		}
-	}
-
-	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));
-
-	return;
+	return 0;
 }
 
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
  *  Private routines...
@@ -3789,11 +3540,10 @@
 		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 @@
 	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 @@
 			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 @@
 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 @@
 	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 @@
 		 */
 		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 @@
 
 		/* 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 @@
 		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 @@
 			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 @@
 		 */
 		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 @@
 			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 @@
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+/*
+ *	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 @@
 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 @@
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /*
- * 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 @@
 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 @@
 		/* 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 @@
 		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 @@
 		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 @@
 	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 @@
 				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 @@
 	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 @@
 	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 @@
 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 @@
 	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 @@
 			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 @@
 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 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 @@
  *	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 @@
 	int			 patt;
 	int			 repeat;
 	int			 retcode = 0;
+	int			 nfactor =  MPT_ULTRA320;
 	char			 firstPass = 1;
 	char			 doFallback = 0;
 	char			 readPage0;
@@ -5883,14 +5972,17 @@
 	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 @@
 	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 @@
 
 	/* 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 @@
 	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 @@
 			}
 		}
 
+		/* 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 @@
 		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 @@
 			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 @@
 	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 @@
 	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 @@
 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 @@
 				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 @@
 /* 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 @@
 	"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
@@ -7146,6 +7282,10 @@
 
 		case OPT_MIN_SYNC_FACTOR:
 			driver_setup.min_sync_fac = val;
+			break;
+
+		case OPT_SAF_TE:
+			driver_setup.saf_te = val;
 			break;
 
 		default:
diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
--- a/drivers/message/fusion/mptscsih.h	Sat Apr  3 19:38:56 2004
+++ b/drivers/message/fusion/mptscsih.h	Sat Apr  3 19:38:56 2004
@@ -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 @@
         MPTSCSIH_DOMAIN_VALIDATION,             \
         MPTSCSIH_MAX_WIDTH,                     \
         MPTSCSIH_MIN_SYNC,                      \
+        MPTSCSIH_SAF_TE,                        \
 }
 
 
diff -Nru a/drivers/message/fusion/scsi3.h b/drivers/message/fusion/scsi3.h
--- a/drivers/message/fusion/scsi3.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/message/fusion/scsi3.h	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c
--- a/drivers/message/i2o/i2o_core.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/message/i2o/i2o_core.c	Sat Apr  3 19:38:44 2004
@@ -1179,7 +1179,7 @@
 		 *	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 -Nru a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
--- a/drivers/mtd/cmdlinepart.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/mtd/cmdlinepart.c	Sat Apr  3 19:38:54 2004
@@ -28,7 +28,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#include <asm/setup.h>
 #include <linux/bootmem.h>
 
 /* error message prefix */
diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c
--- a/drivers/mtd/devices/blkmtd.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/mtd/devices/blkmtd.c	Sat Apr  3 19:38:41 2004
@@ -664,12 +664,12 @@
 	}
 
 	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 -Nru a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c
--- a/drivers/mtd/nand/nand.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/mtd/nand/nand.c	Sat Apr  3 19:38:57 2004
@@ -1060,7 +1060,7 @@
 			goto out;
 
 		/* Update written bytes count */
-		written += mtd->oobblock;;
+		written += mtd->oobblock;
 
 		/* Increment page address */
 		page++;
@@ -1192,7 +1192,7 @@
 	nand_deselect ();
 	spin_unlock_bh (&this->chip_lock);
 
-	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;;
+	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
 	/* Do call back function */
 	if (!ret && instr->callback)
 		instr->callback (instr);
diff -Nru a/drivers/net/3c501.c b/drivers/net/3c501.c
--- a/drivers/net/3c501.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/3c501.c	Sat Apr  3 19:38:40 2004
@@ -306,7 +306,7 @@
 		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 @@
 {
 	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 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 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 @@
 	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 @@
 
 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_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 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 -Nru a/drivers/net/3c503.c b/drivers/net/3c503.c
--- a/drivers/net/3c503.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/3c503.c	Sat Apr  3 19:38:54 2004
@@ -337,6 +337,9 @@
     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 -Nru a/drivers/net/3c507.c b/drivers/net/3c507.c
--- a/drivers/net/3c507.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/3c507.c	Sat Apr  3 19:38:54 2004
@@ -441,7 +441,7 @@
 	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 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 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 @@
 	}
 
 	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 @@
    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 @@
 /* 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_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 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 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 -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c
--- a/drivers/net/3c509.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/3c509.c	Sat Apr  3 19:38:41 2004
@@ -304,7 +304,7 @@
 
 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,21 +355,21 @@
 
 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... */
+	(void) lp;				/* Keep gcc quiet... */
 #ifdef CONFIG_PM
-		if (lp->pmdev)
-			pm_unregister(lp->pmdev);
+	if (lp->pmdev)
+		pm_unregister(lp->pmdev);
 #endif
 #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800)
-		if (lp->type == EL3_PNP)
-			pnp_device_detach(to_pnp_dev(lp->dev));
+	if (lp->type == EL3_PNP)
+		pnp_device_detach(to_pnp_dev(lp->dev));
 #endif
 
-		unregister_netdev (dev);
-		release_region(dev->base_addr, EL3_IO_EXTENT);
-		free_netdev (dev);
+	unregister_netdev (dev);
+	release_region(dev->base_addr, EL3_IO_EXTENT);
+	free_netdev (dev);
 }
 
 static int __init el3_probe(int card_idx)
@@ -397,9 +397,9 @@
 			if (pnp_device_attach(idev) < 0)
 				continue;
 			if (pnp_activate_dev(idev) < 0) {
-			      __again:
-			      	pnp_device_detach(idev);
-			      	continue;
+__again:
+				pnp_device_detach(idev);
+				continue;
 			}
 			if (!pnp_port_valid(idev, 0) || !pnp_irq_valid(idev, 0))
 				goto __again;
@@ -575,7 +575,7 @@
 	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
@@ -612,79 +612,80 @@
 }
 
 #ifdef CONFIG_MCA
-static int __init el3_mca_probe(struct device *device) {
-		/* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch,
-		 * heavily modified by Chris Beauregard
-		 * (cpbeaure@csclub.uwaterloo.ca) to support standard MCA
-		 * probing.
-		 *
-		 * redone for multi-card detection by ZP Gu (zpg@castle.net)
-		 * now works as a module */
-
-		struct el3_private *lp;
-		short i;
-		int ioaddr, irq, if_port;
-		u16 phys_addr[3];
-		struct net_device *dev = NULL;
-		u_char pos4, pos5;
-		struct mca_device *mdev = to_mca_device(device);
-		int slot = mdev->slot;
-		int err;
-
-		pos4 = mca_device_read_stored_pos(mdev, 4);
-		pos5 = mca_device_read_stored_pos(mdev, 5);
-
-		ioaddr = ((short)((pos4&0xfc)|0x02)) << 8;
-		irq = pos5 & 0x0f;
-
-
-		printk("3c529: found %s at slot %d\n",
-			   el3_mca_adapter_names[mdev->index], slot + 1);
-
-		/* claim the slot */
-		strncpy(mdev->name, el3_mca_adapter_names[mdev->index],
-				sizeof(mdev->name));
-		mca_device_set_claim(mdev, 1);
-
-		if_port = pos4 & 0x03;
-
-		irq = mca_device_transform_irq(mdev, irq);
-		ioaddr = mca_device_transform_ioport(mdev, ioaddr); 
-		if (el3_debug > 2) {
-				printk("3c529: irq %d  ioaddr 0x%x  ifport %d\n", irq, ioaddr, if_port);
-		}
-		EL3WINDOW(0);
-		for (i = 0; i < 3; i++) {
-				phys_addr[i] = htons(read_eeprom(ioaddr, i));
-		}
+static int __init el3_mca_probe(struct device *device)
+{
+	/* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch,
+	 * heavily modified by Chris Beauregard
+	 * (cpbeaure@csclub.uwaterloo.ca) to support standard MCA
+	 * probing.
+	 *
+	 * redone for multi-card detection by ZP Gu (zpg@castle.net)
+	 * now works as a module */
 
-		dev = alloc_etherdev(sizeof (struct el3_private));
-		if (dev == NULL) {
-				release_region(ioaddr, EL3_IO_EXTENT);
-				return -ENOMEM;
-		}
+	struct el3_private *lp;
+	short i;
+	int ioaddr, irq, if_port;
+	u16 phys_addr[3];
+	struct net_device *dev = NULL;
+	u_char pos4, pos5;
+	struct mca_device *mdev = to_mca_device(device);
+	int slot = mdev->slot;
+	int err;
+
+	pos4 = mca_device_read_stored_pos(mdev, 4);
+	pos5 = mca_device_read_stored_pos(mdev, 5);
 
-		SET_MODULE_OWNER(dev);
-		netdev_boot_setup_check(dev);
+	ioaddr = ((short)((pos4&0xfc)|0x02)) << 8;
+	irq = pos5 & 0x0f;
 
-		memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
-		dev->base_addr = ioaddr;
-		dev->irq = irq;
-		dev->if_port = if_port;
-		lp = dev->priv;
-		lp->dev = device;
-		lp->type = EL3_MCA;
-		device->driver_data = dev;
-		err = el3_common_init(dev);
-
-		if (err) {
-			device->driver_data = NULL;
-			free_netdev(dev);
+
+	printk("3c529: found %s at slot %d\n",
+		   el3_mca_adapter_names[mdev->index], slot + 1);
+
+	/* claim the slot */
+	strncpy(mdev->name, el3_mca_adapter_names[mdev->index],
+			sizeof(mdev->name));
+	mca_device_set_claim(mdev, 1);
+
+	if_port = pos4 & 0x03;
+
+	irq = mca_device_transform_irq(mdev, irq);
+	ioaddr = mca_device_transform_ioport(mdev, ioaddr); 
+	if (el3_debug > 2) {
+			printk("3c529: irq %d  ioaddr 0x%x  ifport %d\n", irq, ioaddr, if_port);
+	}
+	EL3WINDOW(0);
+	for (i = 0; i < 3; i++) {
+			phys_addr[i] = htons(read_eeprom(ioaddr, i));
+	}
+
+	dev = alloc_etherdev(sizeof (struct el3_private));
+	if (dev == NULL) {
+			release_region(ioaddr, EL3_IO_EXTENT);
 			return -ENOMEM;
-		}
+	}
 
-		el3_cards++;
-		return 0;
+	SET_MODULE_OWNER(dev);
+	netdev_boot_setup_check(dev);
+
+	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	dev->if_port = if_port;
+	lp = netdev_priv(dev);
+	lp->dev = device;
+	lp->type = EL3_MCA;
+	device->driver_data = dev;
+	err = el3_common_init(dev);
+
+	if (err) {
+		device->driver_data = NULL;
+		free_netdev(dev);
+		return -ENOMEM;
+	}
+
+	el3_cards++;
+	return 0;
 }
 		
 #endif /* CONFIG_MCA */
@@ -713,15 +714,15 @@
 	irq = inw(ioaddr + WN0_IRQ) >> 12;
 	if_port = inw(ioaddr + 6)>>14;
 	for (i = 0; i < 3; i++)
-			phys_addr[i] = htons(read_eeprom(ioaddr, i));
+		phys_addr[i] = htons(read_eeprom(ioaddr, i));
 
 	/* Restore the "Product ID" to the EEPROM read register. */
 	read_eeprom(ioaddr, 3);
 
 	dev = alloc_etherdev(sizeof (struct el3_private));
 	if (dev == NULL) {
-			release_region(ioaddr, EL3_IO_EXTENT);
-			return -ENOMEM;
+		release_region(ioaddr, EL3_IO_EXTENT);
+		return -ENOMEM;
 	}
 
 	SET_MODULE_OWNER(dev);
@@ -732,7 +733,7 @@
 	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);
@@ -755,12 +756,12 @@
  * The net dev must be stored in the driver_data field */
 static int __devexit el3_device_remove (struct device *device)
 {
-		struct net_device *dev;
+	struct net_device *dev;
 
-		dev  = device->driver_data;
+	dev  = device->driver_data;
 
-		el3_common_remove (dev);
-		return 0;
+	el3_common_remove (dev);
+	return 0;
 }
 #endif
 
@@ -810,7 +811,8 @@
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
 	i = request_irq(dev->irq, &el3_interrupt, 0, dev->name, dev);
-	if (i) return i;
+	if (i)
+		return i;
 
 	EL3WINDOW(0);
 	if (el3_debug > 3)
@@ -829,7 +831,7 @@
 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 +851,7 @@
 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;
 
@@ -891,8 +893,8 @@
 	 *	time sensitive devices.
 	 */
 
-    	spin_lock_irqsave(&lp->lock, flags);
-	    
+	spin_lock_irqsave(&lp->lock, flags);
+
 	/* Put out the doubleword header... */
 	outw(skb->len, ioaddr + TX_FIFO);
 	outw(0x00, ioaddr + TX_FIFO);
@@ -943,7 +945,7 @@
 		return IRQ_NONE;
 	}
 
-	lp = (struct el3_private *)dev->priv;
+	lp = netdev_priv(dev);
 	spin_lock(&lp->lock);
 
 	ioaddr = dev->base_addr;
@@ -975,7 +977,7 @@
 				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 +1024,7 @@
 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 +1045,7 @@
 	*/
 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 +1075,7 @@
 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 +1147,7 @@
 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) {
@@ -1164,7 +1166,7 @@
 		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast, ioaddr + EL3_CMD);
 	}
 	else
-                outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+		outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
 	spin_unlock_irqrestore(&lp->lock, flags);
 }
 
@@ -1172,7 +1174,7 @@
 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);
@@ -1183,10 +1185,10 @@
 	/* Switching back to window 0 disables the IRQ. */
 	EL3WINDOW(0);
 	if (lp->type != EL3_EISA) {
-	    /* But we explicitly zero the IRQ line select anyway. Don't do
-	     * it on EISA cards, it prevents the module from getting an
-	     * IRQ after unload+reload... */
-	    outw(0x0f00, ioaddr + WN0_IRQ);
+		/* But we explicitly zero the IRQ line select anyway. Don't do
+		 * it on EISA cards, it prevents the module from getting an
+		 * IRQ after unload+reload... */
+		outw(0x0f00, ioaddr + WN0_IRQ);
 	}
 
 	return 0;
@@ -1317,7 +1319,7 @@
 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 +1560,7 @@
 		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 +1587,7 @@
 		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);
@@ -1654,13 +1656,13 @@
 
 #ifdef CONFIG_EISA
 	if (eisa_driver_register (&el3_eisa_driver) < 0) {
-			eisa_driver_unregister (&el3_eisa_driver);
+		eisa_driver_unregister (&el3_eisa_driver);
 	}
 #endif
 #ifdef CONFIG_MCA
 	mca_register_driver(&el3_mca_driver);
 #endif
-	return el3_cards ? 0 : -ENODEV;
+	return 0;
 }
 
 static void __exit el3_cleanup_module(void)
@@ -1668,7 +1670,7 @@
 	struct net_device *next_dev;
 
 	while (el3_root_dev) {
-		struct el3_private *lp = (struct el3_private *)el3_root_dev->priv;
+		struct el3_private *lp = netdev_priv(el3_root_dev);
 
 		next_dev = lp->next_dev;
 		el3_common_remove (el3_root_dev);
@@ -1686,11 +1688,3 @@
 module_init (el3_init_module);
 module_exit (el3_cleanup_module);
 
-/*
- * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c509.c"
- *  version-control: t
- *  kept-new-versions: 5
- *  tab-width: 4
- * End:
- */
diff -Nru a/drivers/net/3c527.c b/drivers/net/3c527.c
--- a/drivers/net/3c527.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/3c527.c	Sat Apr  3 19:38:44 2004
@@ -226,7 +226,7 @@
 
 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 @@
 	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 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(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 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_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 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 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_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_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 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 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 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_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_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 @@
 	}
  
 	ioaddr = dev->base_addr;
-	lp = (struct mc32_local *)dev->priv;
+	lp = netdev_priv(dev);
 
 	/* See whats cooking */
 
@@ -1450,7 +1450,7 @@
 
 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 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 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 -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/3c59x.c	Sat Apr  3 19:38:40 2004
@@ -927,6 +927,18 @@
 
 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 @@
 		BUG();
 	}
 
-	vp = dev->priv;
+	vp = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 	
 	unregister_netdev (dev);
@@ -1115,7 +1127,7 @@
 	}
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, gendev);
-	vp = dev->priv;
+	vp = netdev_priv(dev);
 
 	option = global_options;
 
@@ -1463,6 +1475,9 @@
 	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 @@
 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 @@
 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 @@
 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 @@
 
 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_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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 
 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
 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 @@
 			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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 
 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 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 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 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 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 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 @@
 /* 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 @@
 		BUG();
 	}
 
-	vp = dev->priv;
+	vp = netdev_priv(dev);
 
 	/* AKPM: FIXME: we should have
 	 *	if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
diff -Nru a/drivers/net/7990.c b/drivers/net/7990.c
--- a/drivers/net/7990.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/7990.c	Sat Apr  3 19:38:54 2004
@@ -99,7 +99,7 @@
 /* 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 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_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_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 @@
 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 @@
 
 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_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 @@
 
 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 @@
 
 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 @@
 /* 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 @@
 
 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 -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c
--- a/drivers/net/8139too.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/8139too.c	Sat Apr  3 19:38:40 2004
@@ -113,6 +113,7 @@
 #include <linux/suspend.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/irq.h>
 
 #define RTL8139_DRIVER_NAME   DRV_NAME " Fast Ethernet driver " DRV_VERSION
 #define PFX DRV_NAME ": "
@@ -968,12 +969,11 @@
 	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 -Nru a/drivers/net/82596.c b/drivers/net/82596.c
--- a/drivers/net/82596.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/82596.c	Sat Apr  3 19:38:54 2004
@@ -458,7 +458,7 @@
  
 static void i596_display_data(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	struct i596_cmd *cmd;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -528,7 +528,7 @@
 
 static inline void init_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = dev->priv;
 	int i;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -579,7 +579,7 @@
 
 static inline void remove_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = dev->priv;
 	struct i596_rbd *rbd;
 	int i;
 
@@ -593,7 +593,7 @@
 
 static void rebuild_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	int i;
 
 	/* Ensure rx frame/buffer descriptors are tidy */
@@ -612,7 +612,7 @@
 
 static int init_i596_mem(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET)
 	short ioaddr = dev->base_addr;
 #endif
@@ -765,7 +765,7 @@
 
 static inline int i596_rx(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = dev->priv;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 	int frames = 0;
@@ -960,7 +960,7 @@
 
 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 = dev->priv;
 	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
@@ -1030,7 +1030,7 @@
 
 static void i596_tx_timeout (struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
@@ -1059,7 +1059,7 @@
 
 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 = dev->priv;
 	struct tx_cmd *tx_cmd;
 	struct i596_tbd *tbd;
 	short length = skb->len;
@@ -1245,7 +1245,7 @@
 
 	dev->priv = (void *)(dev->mem_start);
 
-	lp = (struct i596_private *) dev->priv;
+	lp = dev->priv;
 	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 @@
 	}
 
 	ioaddr = dev->base_addr;
-	lp = (struct i596_private *) dev->priv;
+	lp = dev->priv;
 
 	spin_lock (&lp->lock);
 
@@ -1448,7 +1448,7 @@
 
 static int i596_close(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	unsigned long flags;
 
 	netif_stop_queue(dev);
@@ -1495,7 +1495,7 @@
 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 = dev->priv;
 
 	return &lp->stats;
 }
@@ -1506,7 +1506,7 @@
 
 static void set_multicast_list(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	int config = 0, cnt;
 
 	DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n",
diff -Nru a/drivers/net/8390.c b/drivers/net/8390.c
--- a/drivers/net/8390.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/8390.c	Sat Apr  3 19:38:41 2004
@@ -516,6 +516,15 @@
 	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 @@
 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 -Nru a/drivers/net/8390.h b/drivers/net/8390.h
--- a/drivers/net/8390.h	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/8390.h	Sat Apr  3 19:38:54 2004
@@ -39,6 +39,10 @@
 #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 -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/Kconfig	Sat Apr  3 19:38:55 2004
@@ -2048,8 +2048,8 @@
 	  
 	  If you want to compile this driver as a module ( = code which can be
 	  inserted in and removed from the running kernel whenever you want),
-	  say M here and read Documentation/modules.txt. This is recommended.
-	  The module will be called sk98lin. This is recommended.
+	  say M here and read Documentation/kbuild/modules.txt. The module will
+	  be called sk98lin. This is recommended.
 
 config TIGON3
 	tristate "Broadcom Tigon3 support"
@@ -2494,6 +2494,13 @@
 
 	  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"
 
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/Makefile	Sat Apr  3 19:38:42 2004
@@ -188,3 +188,4 @@
 obj-$(CONFIG_HAMRADIO) += hamradio/
 obj-$(CONFIG_IRDA) += irda/
 
+obj-$(CONFIG_NETCONSOLE) += netconsole.o
diff -Nru a/drivers/net/a2065.c b/drivers/net/a2065.c
--- a/drivers/net/a2065.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/a2065.c	Sat Apr  3 19:38:44 2004
@@ -164,7 +164,7 @@
 /* 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 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_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 @@
 
 	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 @@
 
 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_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 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 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 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 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 @@
 /* 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_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 @@
 	}
 
 	SET_MODULE_OWNER(dev);
-	priv = dev->priv;
+	priv = netdev_priv(dev);
 
 	r1->name = dev->name;
 	r2->name = dev->name;
diff -Nru a/drivers/net/ac3200.c b/drivers/net/ac3200.c
--- a/drivers/net/ac3200.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/ac3200.c	Sat Apr  3 19:38:45 2004
@@ -276,6 +276,9 @@
 
 	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 -Nru a/drivers/net/acenic.h b/drivers/net/acenic.h
--- a/drivers/net/acenic.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/acenic.h	Sat Apr  3 19:38:43 2004
@@ -696,7 +696,7 @@
 	char			name[48];
 #ifdef INDEX_DEBUG
 	spinlock_t		debug_lock
-				__attribute__ ((aligned (SMP_CACHE_BYTES)));;
+				__attribute__ ((aligned (SMP_CACHE_BYTES)));
 	u32			last_tx, last_std_rx, last_mini_rx;
 #endif
 	struct net_device_stats stats;
diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
--- a/drivers/net/amd8111e.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/amd8111e.c	Sat Apr  3 19:38:44 2004
@@ -174,7 +174,7 @@
 */ 
 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 @@
 */ 
 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 @@
 */
 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 @@
 */
 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 @@
 */
 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 @@
  */
 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 @@
 	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 @@
 */
 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 @@
 */
 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 @@
 */
 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 @@
 */
 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 @@
 */ 
 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 @@
 */
 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 @@
 {
 
 	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 @@
 	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_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 @@
 
 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 @@
 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 @@
 	
 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_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 @@
 */  
 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 @@
 #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_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 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 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_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 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 @@
 	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 @@
 	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 -Nru a/drivers/net/apne.c b/drivers/net/apne.c
--- a/drivers/net/apne.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/apne.c	Sat Apr  3 19:38:56 2004
@@ -333,6 +333,9 @@
     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 -Nru a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
--- a/drivers/net/appletalk/cops.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/appletalk/cops.c	Sat Apr  3 19:38:43 2004
@@ -333,7 +333,7 @@
 
 	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 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_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 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 @@
 {
         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 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 @@
         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 @@
         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_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 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_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_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 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 -Nru a/drivers/net/ariadne.c b/drivers/net/ariadne.c
--- a/drivers/net/ariadne.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/ariadne.c	Sat Apr  3 19:38:45 2004
@@ -184,7 +184,7 @@
     }
 
     SET_MODULE_OWNER(dev);
-    priv = dev->priv;
+    priv = netdev_priv(dev);
 
     r1->name = dev->name;
     r2->name = dev->name;
@@ -333,7 +333,7 @@
 
 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 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 @@
     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 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_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 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 -Nru a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
--- a/drivers/net/arm/am79c961a.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/arm/am79c961a.c	Sat Apr  3 19:38:54 2004
@@ -196,7 +196,7 @@
 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 @@
 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 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 @@
 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 @@
  */
 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_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 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 @@
 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 @@
 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 @@
 	if (!dev)
 		goto out;
 
-	priv = dev->priv;
+	priv = netdev_priv(dev);
 
 	/*
 	 * Fixed address and IRQ lines here.
diff -Nru a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
--- a/drivers/net/arm/ether1.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/arm/ether1.c	Sat Apr  3 19:38:44 2004
@@ -447,7 +447,7 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 	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 -Nru a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
--- a/drivers/net/arm/ether3.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/arm/ether3.c	Sat Apr  3 19:38:56 2004
@@ -121,7 +121,7 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
  */
 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 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_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 @@
 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 @@
 		printk("eth3irq: %d ", irq);
 #endif
 
-	priv = (struct dev_priv *)dev->priv;
+	priv = netdev_priv(dev);
 
 	status = ether3_inw(REG_STATUS);
 
@@ -844,7 +844,7 @@
 		goto free;
 	}
 
-	priv = (struct dev_priv *) dev->priv;
+	priv = netdev_priv(dev);
 	init_timer(&priv->timer);
 
 	/* Reset card...
diff -Nru a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
--- a/drivers/net/arm/etherh.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/arm/etherh.c	Sat Apr  3 19:38:55 2004
@@ -144,7 +144,7 @@
 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 @@
 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 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 		goto out;
 	}
 
-	eh = dev->priv;
+	eh = netdev_priv(dev);
 
 	spin_lock_init(&eh->eidev.page_lock);
 
@@ -653,7 +653,7 @@
 		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 -Nru a/drivers/net/at1700.c b/drivers/net/at1700.c
--- a/drivers/net/at1700.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/at1700.c	Sat Apr  3 19:38:43 2004
@@ -241,7 +241,7 @@
 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 @@
 	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 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 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 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 @@
 	}
 
 	ioaddr = dev->base_addr;
-	lp = (struct net_local *)dev->priv;
+	lp = netdev_priv(dev);
 	
 	spin_lock (&lp->lock);
 	
@@ -808,7 +808,7 @@
 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 @@
 /* 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 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 @@
 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 -Nru a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
--- a/drivers/net/atari_bionet.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/atari_bionet.c	Sat Apr  3 19:38:44 2004
@@ -408,7 +408,7 @@
  */
 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 @@
 
 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 @@
  */
 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 @@
 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 @@
  */
 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 @@
  */
 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 -Nru a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
--- a/drivers/net/atari_pamsnet.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/atari_pamsnet.c	Sat Apr  3 19:38:42 2004
@@ -667,7 +667,7 @@
  */
 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 @@
 
 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 @@
  */
 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 @@
 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 @@
  */
 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 @@
  */
 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 -Nru a/drivers/net/atp.c b/drivers/net/atp.c
--- a/drivers/net/atp.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/atp.c	Sat Apr  3 19:38:56 2004
@@ -335,7 +335,7 @@
 	/* 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 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 @@
    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 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 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 @@
 		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 @@
 {
 	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 @@
 		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 @@
 /* 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 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 @@
 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 @@
 
 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_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 -Nru a/drivers/net/b44.c b/drivers/net/b44.c
--- a/drivers/net/b44.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/b44.c	Sat Apr  3 19:38:43 2004
@@ -667,6 +667,10 @@
 	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 @@
 		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)) ||
@@ -1887,6 +1891,8 @@
 
 	if (!netif_running(dev))
 		return 0;
+
+	pci_restore_state(pdev, bp->pci_cfg_state);
 
 	spin_lock_irq(&bp->lock);
 
diff -Nru a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c
--- a/drivers/net/bagetlance.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/bagetlance.c	Sat Apr  3 19:38:40 2004
@@ -594,7 +594,7 @@
 	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 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 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 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 @@
 		return IRQ_NONE;
 	}
 
-	lp = (struct lance_private *)dev->priv;
+	lp = netdev_priv(dev);
 	IO = lp->iobase;
 	AREG = CSR0;
 
@@ -1101,7 +1101,7 @@
 
 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_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 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 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 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 -Nru a/drivers/net/bmac.c b/drivers/net/bmac.c
--- a/drivers/net/bmac.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/bmac.c	Sat Apr  3 19:38:41 2004
@@ -226,7 +226,7 @@
 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 @@
 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 @@
 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 @@
 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 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_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_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 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 @@
 
 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 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 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 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 @@
 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 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 @@
 
 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 @@
 		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);
@@ -1312,10 +1312,8 @@
 	bmwrite(dev, INTDISABLE, DisableAll);
 
 	rev = addr[0] == 0 && addr[1] == 0xA0;
-	for (j = 0; j < 6; ++j) {
+	for (j = 0; j < 6; ++j)
 		dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
-		printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
-	}
 
 	/* Enable chip without interrupts for now */
 	bmac_enable_and_reset_chip(dev);
@@ -1380,6 +1378,8 @@
 	}
 
 	printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
+	for (j = 0; j < 6; ++j)
+		printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
 	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
 	printk("\n");
 	
@@ -1408,7 +1408,7 @@
 
 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_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 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 @@
 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 @@
 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 @@
 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 -Nru a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
--- a/drivers/net/cs89x0.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/cs89x0.c	Sat Apr  3 19:38:55 2004
@@ -399,7 +399,7 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 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 @@
  	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 @@
 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 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 @@
 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 @@
 
 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 @@
 
 	dev->irq = irq;
 	dev->base_addr = io;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 
 #if ALLOW_DMA
 	if (use_dma) {
diff -Nru a/drivers/net/declance.c b/drivers/net/declance.c
--- a/drivers/net/declance.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/declance.c	Sat Apr  3 19:38:44 2004
@@ -433,7 +433,7 @@
 /* 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 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 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 @@
 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 @@
 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_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 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 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 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 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_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 @@
 	 * 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 @@
 {
 	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 -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c
--- a/drivers/net/dl2k.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/dl2k.c	Sat Apr  3 19:38:43 2004
@@ -874,8 +874,6 @@
 		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 @@
 				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 @@
 						  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 -Nru a/drivers/net/e100.c b/drivers/net/e100.c
--- a/drivers/net/e100.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/e100.c	Sat Apr  3 19:38:56 2004
@@ -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 @@
 				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 @@
 		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 @@
 			(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 @@
 		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 @@
 		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 -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
--- a/drivers/net/e1000/e1000_ethtool.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/e1000/e1000_ethtool.c	Sat Apr  3 19:38:43 2004
@@ -1191,16 +1191,16 @@
 
 	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 -Nru a/drivers/net/e2100.c b/drivers/net/e2100.c
--- a/drivers/net/e2100.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/e2100.c	Sat Apr  3 19:38:55 2004
@@ -269,6 +269,9 @@
 	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 -Nru a/drivers/net/eepro.c b/drivers/net/eepro.c
--- a/drivers/net/eepro.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/eepro.c	Sat Apr  3 19:38:54 2004
@@ -662,7 +662,7 @@
 {
 	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 @@
 }
 
 /* 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 @@
 	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 @@
 	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 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 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 @@
                 return IRQ_NONE;
         }
 
-	lp = (struct eepro_local *)dev->priv;
+	lp = netdev_priv(dev);
 
         spin_lock(&lp->lock);
 
@@ -1235,7 +1235,7 @@
 
 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 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 @@
 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 @@
 {
 	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 @@
 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 @@
 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 @@
 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 -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c
--- a/drivers/net/eepro100.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/eepro100.c	Sat Apr  3 19:38:45 2004
@@ -113,6 +113,7 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/irq.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -654,6 +655,23 @@
 	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 +857,7 @@
 
 	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 +903,9 @@
 	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 +1016,7 @@
 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 +1103,7 @@
 /* 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 +1183,7 @@
 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 +1215,7 @@
 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 +1260,7 @@
 
 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 +1303,7 @@
 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 +1327,8 @@
 		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 +1337,21 @@
 		/* 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 +1383,7 @@
 
 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 +1406,7 @@
 
 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 +1468,7 @@
 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 +1539,7 @@
 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 +1606,7 @@
 	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 +1698,7 @@
 
 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 +1717,29 @@
 	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 +1781,7 @@
 
 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 +1791,7 @@
 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 +1804,8 @@
 		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 +1851,9 @@
 				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 +1863,9 @@
 				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 +1880,8 @@
 				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 +1910,7 @@
 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 +1988,7 @@
 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 +2021,7 @@
 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 +2096,7 @@
 
 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 +2147,7 @@
 */
 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 +2313,8 @@
 		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 +2339,7 @@
 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 +2359,7 @@
 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 +2389,7 @@
 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 -Nru a/drivers/net/eexpress.c b/drivers/net/eexpress.c
--- a/drivers/net/eexpress.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/eexpress.c	Sat Apr  3 19:38:40 2004
@@ -452,7 +452,7 @@
 {
 	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_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 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 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 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 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 @@
 				     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 @@
 		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_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_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 @@
 	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 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 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_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_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_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 @@
 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 -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c
--- a/drivers/net/epic100.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/epic100.c	Sat Apr  3 19:38:43 2004
@@ -1199,8 +1199,6 @@
 			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 @@
 				&& (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 @@
 				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 -Nru a/drivers/net/es3210.c b/drivers/net/es3210.c
--- a/drivers/net/es3210.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/es3210.c	Sat Apr  3 19:38:55 2004
@@ -298,6 +298,9 @@
 
 	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 -Nru a/drivers/net/eth16i.c b/drivers/net/eth16i.c
--- a/drivers/net/eth16i.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/eth16i.c	Sat Apr  3 19:38:55 2004
@@ -486,7 +486,7 @@
 
 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 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_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 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 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 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 @@
 	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_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 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 -Nru a/drivers/net/ethertap.c b/drivers/net/ethertap.c
--- a/drivers/net/ethertap.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/ethertap.c	Sat Apr  3 19:38:42 2004
@@ -121,7 +121,7 @@
 
 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 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 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 __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 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 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 -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c
--- a/drivers/net/fc/iph5526.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/fc/iph5526.c	Sat Apr  3 19:38:42 2004
@@ -238,7 +238,7 @@
 
 static int __init iph5526_probe_pci(struct net_device *dev)
 {
-	struct fc_info *fi = (struct fc_info *)dev->priv;
+	struct fc_info *fi = dev->priv;
 	fi->dev = dev;
 	dev->base_addr = fi->base_addr;
 	dev->irq = fi->irq;
@@ -2908,7 +2908,7 @@
 
 static void iph5526_timeout(struct net_device *dev)
 {
-	struct fc_info *fi = (struct fc_info*)dev->priv;
+	struct fc_info *fi = dev->priv;
 	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 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 = dev->priv;
 	int status = 0;
 	short type = 0;
 	u_long flags;
@@ -3688,7 +3688,7 @@
 
 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 = dev->priv;
 	return (struct net_device_stats *) &fi->fc_stats;
 }
 
diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c
--- a/drivers/net/fealnx.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/fealnx.c	Sat Apr  3 19:38:54 2004
@@ -1303,14 +1303,15 @@
 	/* for the last tx descriptor */
 	np->tx_ring[i - 1].next_desc = np->tx_ring_dma;
 	np->tx_ring[i - 1].next_desc_logical = &np->tx_ring[0];
-
-	return;
 }
 
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&np->lock, flags);
 
 	np->cur_tx_copy->skbuff = skb;
 
@@ -1377,6 +1378,7 @@
 	writel(0, dev->base_addr + TXPDR);
 	dev->trans_start = jiffies;
 
+	spin_unlock_irqrestore(&np->lock, flags);
 	return 0;
 }
 
@@ -1423,6 +1425,8 @@
 	unsigned int num_tx = 0;
 	int handled = 0;
 
+	spin_lock(&np->lock);
+
 	writel(0, dev->base_addr + IMR);
 
 	ioaddr = dev->base_addr;
@@ -1565,6 +1569,8 @@
 
 	writel(np->imrvalue, ioaddr + IMR);
 
+	spin_unlock(&np->lock);
+
 	return IRQ_RETVAL(handled);
 }
 
@@ -1647,10 +1653,6 @@
 				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 +1660,10 @@
 			    (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 +1674,15 @@
 				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 +1703,10 @@
 
 			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 -Nru a/drivers/net/fec.c b/drivers/net/fec.c
--- a/drivers/net/fec.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/fec.c	Sat Apr  3 19:38:41 2004
@@ -269,7 +269,7 @@
 	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 @@
 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 @@
 	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 @@
 	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 @@
 	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 @@
 
 	/* 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_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_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_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_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 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 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 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 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_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_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_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_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 @@
 	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 @@
 	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 @@
 #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 @@
 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 @@
 
 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 @@
 	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 @@
   */
 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 @@
 
 	fecp = fec_hwp;
 
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 
 	/* Whack a reset.  We should wait for this.
 	*/
@@ -1924,7 +1924,7 @@
 	struct fec_enet_private *fep;
 
 	fecp = fec_hwp;
-	fep = dev->priv;
+	fep = netdev_priv(dev);
 
 	fecp->fec_x_cntrl = 0x01;	/* Graceful transmit stop */
 
diff -Nru a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
--- a/drivers/net/forcedeth.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/forcedeth.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 #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 @@
 	u32 linkspeed;
 	int duplex;
 	int phyaddr;
+	int wolenabled;
 
 	/* General data: RO fields */
 	dma_addr_t ring_addr;
@@ -468,12 +473,12 @@
 	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 @@
 	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 @@
 	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 @@
 			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 @@
 }
 
 /*
- * 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 @@
 		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 @@
 	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 @@
 	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 @@
 	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_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_ring(struct net_device *dev)
 {
-	drain_tx(dev);
-	drain_rx(dev);
+	nv_drain_tx(dev);
+	nv_drain_rx(dev);
 }
 
 /*
@@ -759,11 +798,11 @@
 }
 
 /*
- * 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 @@
 
 		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 @@
 	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 @@
 
 		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 @@
 
 		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 @@
 	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 @@
 	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 @@
 
 	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 @@
 	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 @@
 
 		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 @@
 
 		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 @@
 
 			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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 
 	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 @@
 
 	drain_ring(dev);
 
+	if (np->wolenabled)
+		nv_start_rx(dev);
+
 	/* FIXME: power down nic */
 
 	return 0;
@@ -1367,10 +1410,10 @@
 
 	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) {
@@ -1458,6 +1501,10 @@
 	dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev),
 			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)
diff -Nru a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
--- a/drivers/net/gt96100eth.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/gt96100eth.c	Sat Apr  3 19:38:54 2004
@@ -277,7 +277,7 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 		goto out1;
 	}
 
-	gp = dev->priv;
+	gp = netdev_priv(dev);
 
 	memset(gp, 0, sizeof(*gp)); // clear it
 
@@ -839,7 +839,7 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 -Nru a/drivers/net/hamachi.c b/drivers/net/hamachi.c
--- a/drivers/net/hamachi.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/hamachi.c	Sat Apr  3 19:38:56 2004
@@ -1498,8 +1498,10 @@
 		
 		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 @@
 #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 @@
 				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 -Nru a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
--- a/drivers/net/hamradio/6pack.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/hamradio/6pack.c	Sat Apr  3 19:38:41 2004
@@ -3,15 +3,13 @@
  *		devices like TTY. It interfaces between a raw TTY and the
  *		kernel's AX.25 protocol layers.
  *
- * Version:	@(#)6pack.c	0.3.0	04/07/98
- *
  * Authors:	Andreas Könsgen <ajk@iehk.rwth-aachen.de>
+ *              Ralf Baechle DO1GRB <ralf@linux-mips.org>
  *
- * Quite a lot of stuff "stolen" by Jörg Reuter from slip.c, written by
+ * Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
  *
  *		Laurence Culhane, <loz@holmes.demon.co.uk>
  *		Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- *
  */
 
 #include <linux/config.h>
@@ -31,20 +29,23 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
+#include <linux/spinlock.h>
 #include <linux/if_arp.h>
 #include <linux/init.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
+#include <asm/semaphore.h>
+#include <asm/atomic.h>
 
 #define SIXPACK_VERSION    "Revision: 0.3.0"
 
 /* sixpack priority commands */
-#define SIXP_SEOF	0x40	/* start and end of a 6pack frame */
-#define SIXP_TX_URUN	0x48	/* transmit overrun */
-#define SIXP_RX_ORUN	0x50	/* receive overrun */
-#define SIXP_RX_BUF_OVL	0x58	/* receive buffer overflow */
+#define SIXP_SEOF		0x40	/* start and end of a 6pack frame */
+#define SIXP_TX_URUN		0x48	/* transmit overrun */
+#define SIXP_RX_ORUN		0x50	/* receive overrun */
+#define SIXP_RX_BUF_OVL		0x58	/* receive buffer overflow */
 
-#define SIXP_CHKSUM	0xFF	/* valid checksum of a 6pack frame */
+#define SIXP_CHKSUM		0xFF	/* valid checksum of a 6pack frame */
 
 /* masks to get certain bits out of the status bytes sent by the TNC */
 
@@ -78,23 +79,20 @@
 #define SIXP_MTU			256	/* Default MTU */
 
 enum sixpack_flags {
-	SIXPF_INUSE,	/* Channel in use	*/
 	SIXPF_ERROR,	/* Parity, etc. error	*/
 };
 
 struct sixpack {
-	int			magic;
-
 	/* Various fields. */
-	struct tty_struct	*tty;		/* ptr to TTY structure		*/
-	struct net_device	*dev;		/* easy for intr handling	*/
+	struct tty_struct	*tty;		/* ptr to TTY structure	*/
+	struct net_device	*dev;		/* easy for intr handling  */
 
 	/* These are pointers to the malloc()ed frame buffers. */
-	unsigned char		*rbuff;		/* receiver buffer		*/
-	int			rcount;         /* received chars counter       */
-	unsigned char		*xbuff;		/* transmitter buffer		*/
-	unsigned char		*xhead;         /* pointer to next byte to XMIT */
-	int			xleft;          /* bytes left in XMIT queue     */
+	unsigned char		*rbuff;		/* receiver buffer	*/
+	int			rcount;         /* received chars counter  */
+	unsigned char		*xbuff;		/* transmitter buffer	*/
+	unsigned char		*xhead;         /* next byte to XMIT */
+	int			xleft;          /* bytes left in XMIT queue  */
 
 	unsigned char		raw_buf[4];
 	unsigned char		cooked_buf[400];
@@ -105,11 +103,11 @@
 	/* 6pack interface statistics. */
 	struct net_device_stats stats;
 
-	int			mtu;		/* Our mtu (to spot changes!)   */
-	int			buffsize;       /* Max buffers sizes            */
+	int			mtu;		/* Our mtu (to spot changes!) */
+	int			buffsize;       /* Max buffers sizes */
 
-	unsigned long		flags;		/* Flag values/ mode etc	*/
-	unsigned char		mode;		/* 6pack mode			*/
+	unsigned long		flags;		/* Flag values/ mode etc */
+	unsigned char		mode;		/* 6pack mode */
 
 	/* 6pack stuff */
 	unsigned char		tx_delay;
@@ -125,112 +123,293 @@
 
 	struct timer_list	tx_t;
 	struct timer_list	resync_t;
+
+	atomic_t		refcnt;
+	struct semaphore	dead_sem;
+	spinlock_t		lock;
 };
 
 #define AX25_6PACK_HEADER_LEN 0
-#define SIXPACK_MAGIC 0x5304
-
-typedef struct sixpack_ctrl {
-	struct sixpack	ctrl;			/* 6pack things			*/
-	struct net_device	dev;		/* the device			*/
-} sixpack_ctrl_t;
-static sixpack_ctrl_t **sixpack_ctrls;
-
-int sixpack_maxdev = SIXP_NRUNIT;	/* Can be overridden with insmod! */
-MODULE_PARM(sixpack_maxdev, "i");
-MODULE_PARM_DESC(sixpack_maxdev, "number of 6PACK devices");
 
 static void sp_start_tx_timer(struct sixpack *);
-static void sp_xmit_on_air(unsigned long);
-static void resync_tnc(unsigned long);
 static void sixpack_decode(struct sixpack *, unsigned char[], int);
 static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
 static int sixpack_init(struct net_device *dev);
 
-static void decode_prio_command(unsigned char, struct sixpack *);
-static void decode_std_command(unsigned char, struct sixpack *);
-static void decode_data(unsigned char, struct sixpack *);
+/*
+ * perform the persistence/slottime algorithm for CSMA access. If the
+ * persistence check was successful, write the data to the serial driver.
+ * Note that in case of DAMA operation, the data is not sent here.
+ */
+
+static void sp_xmit_on_air(unsigned long channel)
+{
+	struct sixpack *sp = (struct sixpack *) channel;
+	int actual;
+	static unsigned char random;
 
-static int tnc_init(struct sixpack *);
+	random = random * 17 + 41;
 
-/* Find a free 6pack channel, and link in this `tty' line. */
-static inline struct sixpack *sp_alloc(void)
+	if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
+		sp->led_state = 0x70;
+		sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+		sp->tx_enable = 1;
+		actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, sp->status2);
+		sp->xleft -= actual;
+		sp->xhead += actual;
+		sp->led_state = 0x60;
+		sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+		sp->status2 = 0;
+	} else
+		sp_start_tx_timer(sp);
+}
+
+/* ----> 6pack timer interrupt handler and friends. <---- */
+static void sp_start_tx_timer(struct sixpack *sp)
 {
-	sixpack_ctrl_t *spp = NULL;
-	int i;
+	int when = sp->slottime;
 
-	for (i = 0; i < sixpack_maxdev; i++) {
-		spp = sixpack_ctrls[i];
+	del_timer(&sp->tx_t);
+	sp->tx_t.data = (unsigned long) sp;
+	sp->tx_t.function = sp_xmit_on_air;
+	sp->tx_t.expires = jiffies + ((when + 1) * HZ) / 100;
+	add_timer(&sp->tx_t);
+}
 
-		if (spp == NULL)
-			break;
+/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
+static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
+{
+	unsigned char *msg, *p = icp;
+	int actual, count;
 
-		if (!test_and_set_bit(SIXPF_INUSE, &spp->ctrl.flags))
-			break;
+	if (len > sp->mtu) {	/* sp->mtu = AX25_MTU = max. PACLEN = 256 */
+		msg = "oversized transmit packet!";
+		goto out_drop;
 	}
 
-	/* Too many devices... */
-	if (i >= sixpack_maxdev)
-		return NULL;
+	if (p[0] > 5) {
+		msg = "invalid KISS command";
+		goto out_drop;
+	}
 
-	/* If no channels are available, allocate one */
-	if (!spp &&
-	    (sixpack_ctrls[i] = (sixpack_ctrl_t *)kmalloc(sizeof(sixpack_ctrl_t),
-						    GFP_KERNEL)) != NULL) {
-		spp = sixpack_ctrls[i];
+	if ((p[0] != 0) && (len > 2)) {
+		msg = "KISS control packet too long";
+		goto out_drop;
 	}
-	memset(spp, 0, sizeof(sixpack_ctrl_t));
 
-	/* Initialize channel control data */
-	set_bit(SIXPF_INUSE, &spp->ctrl.flags);
-	spp->ctrl.tty         = NULL;
-	sprintf(spp->dev.name, "sp%d", i);
-	spp->dev.base_addr    = i;
-	spp->dev.priv         = (void *) &spp->ctrl;
-	spp->dev.next         = NULL;
-	spp->dev.init         = sixpack_init;
-
-	if (spp != NULL) {
-		/* register device so that it can be ifconfig'ed       */
-		/* sixpack_init() will be called as a side-effect         */
-		/* SIDE-EFFECT WARNING: sixpack_init() CLEARS spp->ctrl ! */
-
-		if (register_netdev(&spp->dev) == 0) {
-			set_bit(SIXPF_INUSE, &spp->ctrl.flags);
-			spp->ctrl.dev = &spp->dev;
-			spp->dev.priv = (void *) &spp->ctrl;
-			SET_MODULE_OWNER(&spp->dev);
-			return &spp->ctrl;
-		} else {
-			clear_bit(SIXPF_INUSE, &spp->ctrl.flags);
-			printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n");
-		}
+	if ((p[0] == 0) && (len < 15)) {
+		msg = "bad AX.25 packet to transmit";
+		goto out_drop;
 	}
 
-	return NULL;
+	count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay);
+	set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
+
+	switch (p[0]) {
+	case 1:	sp->tx_delay = p[1];
+		return;
+	case 2:	sp->persistence = p[1];
+		return;
+	case 3:	sp->slottime = p[1];
+		return;
+	case 4:	/* ignored */
+		return;
+	case 5:	sp->duplex = p[1];
+		return;
+	}
+
+	if (p[0] != 0)
+		return;
+
+	/*
+	 * In case of fullduplex or DAMA operation, we don't take care about the
+	 * state of the DCD or of any timers, as the determination of the
+	 * correct time to send is the job of the AX.25 layer. We send
+	 * immediately after data has arrived.
+	 */
+	if (sp->duplex == 1) {
+		sp->led_state = 0x70;
+		sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+		sp->tx_enable = 1;
+		actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, count);
+		sp->xleft = count - actual;
+		sp->xhead = sp->xbuff + actual;
+		sp->led_state = 0x60;
+		sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+	} else {
+		sp->xleft = count;
+		sp->xhead = sp->xbuff;
+		sp->status2 = count;
+		if (sp->duplex == 0)
+			sp_start_tx_timer(sp);
+	}
+
+	return;
+
+out_drop:
+	sp->stats.tx_dropped++;
+	netif_start_queue(sp->dev);
+	printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
+	return;
 }
 
+/* Encapsulate an IP datagram and kick it into a TTY queue. */
+
+static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct sixpack *sp = netdev_priv(dev);
+
+	spin_lock_bh(&sp->lock);
+	/* We were not busy, so we are now... :-) */
+	netif_stop_queue(dev);
+	sp->stats.tx_bytes += skb->len;
+	sp_encaps(sp, skb->data, skb->len);
+	spin_unlock_bh(&sp->lock);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+static int sp_open_dev(struct net_device *dev)
+{
+	struct sixpack *sp = netdev_priv(dev);
+
+	if (sp->tty == NULL)
+		return -ENODEV;
+	return 0;
+}
+
+/* Close the low-level part of the 6pack channel. */
+static int sp_close(struct net_device *dev)
+{
+	struct sixpack *sp = netdev_priv(dev);
+
+	spin_lock_bh(&sp->lock);
+	if (sp->tty) {
+		/* TTY discipline is running. */
+		clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
+	}
+	netif_stop_queue(dev);
+	spin_unlock_bh(&sp->lock);
+
+	return 0;
+}
+
+/* Return the frame type ID */
+static int sp_header(struct sk_buff *skb, struct net_device *dev,
+	unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+#ifdef CONFIG_INET
+	if (type != htons(ETH_P_AX25))
+		return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
+#endif
+	return 0;
+}
+
+static struct net_device_stats *sp_get_stats(struct net_device *dev)
+{
+	struct sixpack *sp = netdev_priv(dev);
+	return &sp->stats;
+}
+
+static int sp_set_dev_mac_address(struct net_device *dev, void *addr)
+{
+	struct sockaddr *sa = addr;
+	memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);
+	return 0;
+}
+
+static int sp_rebuild_header(struct sk_buff *skb)
+{
+#ifdef CONFIG_INET
+	return ax25_rebuild_header(skb);
+#else
+	return 0;
+#endif
+}
+
+static void sp_setup(struct net_device *dev)
+{
+	static char ax25_bcast[AX25_ADDR_LEN] =
+		{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
+	static char ax25_test[AX25_ADDR_LEN] =
+		{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
+
+	/* Finish setting up the DEVICE info. */
+	dev->init		= sixpack_init;
+	dev->mtu		= SIXP_MTU;
+	dev->hard_start_xmit	= sp_xmit;
+	dev->open		= sp_open_dev;
+	dev->destructor		= free_netdev;
+	dev->stop		= sp_close;
+	dev->hard_header	= sp_header;
+	dev->get_stats	        = sp_get_stats;
+	dev->set_mac_address    = sp_set_dev_mac_address;
+	dev->hard_header_len	= AX25_MAX_HEADER_LEN;
+	dev->addr_len		= AX25_ADDR_LEN;
+	dev->type		= ARPHRD_AX25;
+	dev->tx_queue_len	= 10;
+	dev->rebuild_header	= sp_rebuild_header;
+	dev->tx_timeout		= NULL;
+
+	/* Only activated in AX.25 mode */
+	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
+	memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
+
+	SET_MODULE_OWNER(dev);
+
+	/* New-style flags. */
+	dev->flags		= 0;
+}
+
+/* Find a free 6pack channel, and link in this `tty' line. */
+static inline struct sixpack *sp_alloc(void)
+{
+	struct sixpack *sp = NULL;
+	struct net_device *dev = NULL;
+
+	dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
+	if (!dev)
+		return NULL;
+
+	sp = netdev_priv(dev);
+	sp->dev = dev;
+
+	spin_lock_init(&sp->lock);
+
+	if (register_netdev(dev))
+		goto out_free;
+
+	return sp;
+
+out_free:
+	printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n");
+
+	free_netdev(dev);
+
+	return NULL;
+}
 
 /* Free a 6pack channel. */
 static inline void sp_free(struct sixpack *sp)
 {
-	/* Free all 6pack frame buffers. */
-	if (sp->rbuff)
-		kfree(sp->rbuff);
-	sp->rbuff = NULL;
-	if (sp->xbuff)
-		kfree(sp->xbuff);
-	sp->xbuff = NULL;
+	void * tmp;
 
-	if (!test_and_clear_bit(SIXPF_INUSE, &sp->flags))
-		printk(KERN_WARNING "%s: sp_free for already free unit.\n", sp->dev->name);
+	/* Free all 6pack frame buffers. */
+	if ((tmp = xchg(&sp->rbuff, NULL)) != NULL)
+		kfree(tmp);
+	if ((tmp = xchg(&sp->xbuff, NULL)) != NULL)
+		kfree(tmp);
 }
 
 
 /* Send one completely decapsulated IP datagram to the IP layer. */
 
-/* This is the routine that sends the received data to the kernel AX.25.
-   'cmd' is the KISS command. For AX.25 data, it is zero. */
+/*
+ * This is the routine that sends the received data to the kernel AX.25.
+ * 'cmd' is the KISS command. For AX.25 data, it is zero.
+ */
 
 static void sp_bump(struct sixpack *sp, char cmd)
 {
@@ -238,98 +417,60 @@
 	int count;
 	unsigned char *ptr;
 
-	count = sp->rcount+1;
+	count = sp->rcount + 1;
 
 	sp->stats.rx_bytes += count;
 
-	if ((skb = dev_alloc_skb(count)) == NULL) {
-		printk(KERN_DEBUG "%s: memory squeeze, dropping packet.\n", sp->dev->name);
-		sp->stats.rx_dropped++;
-		return;
-	}
+	if ((skb = dev_alloc_skb(count)) == NULL)
+		goto out_mem;
 
 	skb->dev = sp->dev;
 	ptr = skb_put(skb, count);
 	*ptr++ = cmd;	/* KISS command */
 
-	memcpy(ptr, (sp->cooked_buf)+1, count);
+	memcpy(ptr, sp->cooked_buf + 1, count);
 	skb->mac.raw = skb->data;
 	skb->protocol = htons(ETH_P_AX25);
 	netif_rx(skb);
 	sp->dev->last_rx = jiffies;
 	sp->stats.rx_packets++;
+
+	return;
+
+out_mem:
+	sp->stats.rx_dropped++;
 }
 
 
 /* ----------------------------------------------------------------------- */
 
-/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
-static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
+/*
+ * We have a potential race on dereferencing tty->disc_data, because the tty
+ * layer provides no locking at all - thus one cpu could be running
+ * sixpack_receive_buf while another calls sixpack_close, which zeroes
+ * tty->disc_data and frees the memory that sixpack_receive_buf is using.  The
+ * best way to fix this is to use a rwlock in the tty struct, but for now we
+ * use a single global rwlock for all ttys in ppp line discipline.
+ */
+static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
+                                                                                
+static struct sixpack *sp_get(struct tty_struct *tty)
 {
-	unsigned char *p;
-	int actual, count;
-
-	if (len > sp->mtu) {	/* sp->mtu = AX25_MTU = max. PACLEN = 256 */
-		printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n", sp->dev->name);
-		sp->stats.tx_dropped++;
-		netif_start_queue(sp->dev);
-		return;
-	}
-
-	p = icp;
-
-	if (p[0] > 5) {
-		printk(KERN_DEBUG "%s: invalid KISS command -- dropped\n", sp->dev->name);
-		netif_start_queue(sp->dev);
-		return;
-	}
-
-	if ((p[0] != 0) && (len > 2)) {
-		printk(KERN_DEBUG "%s: KISS control packet too long -- dropped\n", sp->dev->name);
-		netif_start_queue(sp->dev);
-		return;
-	}
-
-	if ((p[0] == 0) && (len < 15)) {
-		printk(KERN_DEBUG "%s: bad AX.25 packet to transmit -- dropped\n", sp->dev->name);
-		netif_start_queue(sp->dev);
-		sp->stats.tx_dropped++;
-		return;
-	}
+	struct sixpack *sp;
 
-	count = encode_sixpack(p, (unsigned char *) sp->xbuff, len, sp->tx_delay);
-	sp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+	read_lock(&disc_data_lock);
+	sp = tty->disc_data;
+	if (sp)
+		atomic_inc(&sp->refcnt);
+	read_unlock(&disc_data_lock);
 
-	switch (p[0]) {
-		case 1:	sp->tx_delay = p[1];		return;
-		case 2:	sp->persistence = p[1];		return;
-		case 3: sp->slottime = p[1];		return;
-		case 4: /* ignored */			return;
-		case 5: sp->duplex = p[1];		return;
-	}
+	return sp;
+}
 
-	if (p[0] == 0) {
-		/* in case of fullduplex or DAMA operation, we don't take care
-		   about the state of the DCD or of any timers, as the determination
-		   of the correct time to send is the job of the AX.25 layer. We send
-		   immediately after data has arrived. */
-		if (sp->duplex == 1) {
-			sp->led_state = 0x70;
-			sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
-			sp->tx_enable = 1;
-			actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, count);
-			sp->xleft = count - actual;
-			sp->xhead = sp->xbuff + actual;
-			sp->led_state = 0x60;
-			sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
-		} else {
-			sp->xleft = count;
-			sp->xhead = sp->xbuff;
-			sp->status2 = count;
-			if (sp->duplex == 0)
-				sp_start_tx_timer(sp);
-		}
-	}
+static void sp_put(struct sixpack *sp)
+{
+	if (atomic_dec_and_test(&sp->refcnt))
+		up(&sp->dead_sem);
 }
 
 /*
@@ -338,22 +479,17 @@
  */
 static void sixpack_write_wakeup(struct tty_struct *tty)
 {
+	struct sixpack *sp = sp_get(tty);
 	int actual;
-	struct sixpack *sp = (struct sixpack *) tty->disc_data;
-
-	/* First make sure we're connected. */
-	if (!sp || sp->magic != SIXPACK_MAGIC ||
-	    !netif_running(sp->dev))
-		return;
 
 	if (sp->xleft <= 0)  {
 		/* Now serial buffer is almost free & we can start
 		 * transmission of another packet */
 		sp->stats.tx_packets++;
-		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 		sp->tx_enable = 0;
 		netif_wake_queue(sp->dev);
-		return;
+		goto out;
 	}
 
 	if (sp->tx_enable == 1) {
@@ -361,79 +497,34 @@
 		sp->xleft -= actual;
 		sp->xhead += actual;
 	}
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* Encapsulate an IP datagram and kick it into a TTY queue. */
-
-static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-	struct sixpack *sp = (struct sixpack *) dev->priv;
-
-	/* We were not busy, so we are now... :-) */
-	netif_stop_queue(dev);
-	sp->stats.tx_bytes += skb->len;
-	sp_encaps(sp, skb->data, skb->len);
-	dev_kfree_skb(skb);
-	return 0;
-}
-
-
-/* perform the persistence/slottime algorithm for CSMA access. If the persistence
-   check was successful, write the data to the serial driver. Note that in case
-   of DAMA operation, the data is not sent here. */
 
-static void sp_xmit_on_air(unsigned long channel)
-{
-	struct sixpack *sp = (struct sixpack *) channel;
-	int actual;
-	static unsigned char random;
-
-	random = random * 17 + 41;
-
-	if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
-		sp->led_state = 0x70;
-		sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
-		sp->tx_enable = 1;
-		actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, sp->status2);
-		sp->xleft -= actual;
-		sp->xhead += actual;
-		sp->led_state = 0x60;
-		sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
-		sp->status2 = 0;
-	} else
-		sp_start_tx_timer(sp);
+out:
+	sp_put(sp);
 }
 
+/* ----------------------------------------------------------------------- */
 
-/* Return the frame type ID */
-static int sp_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	  void *daddr, void *saddr, unsigned len)
+/* Open the low-level part of the 6pack channel. */
+static int sp_open(struct net_device *dev)
 {
-#ifdef CONFIG_INET
-	if (type != htons(ETH_P_AX25))
-		return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
-#endif
-	return 0;
-}
+	struct sixpack *sp = netdev_priv(dev);
+	char *rbuff, *xbuff = NULL;
+	int err = -ENOBUFS;
+	unsigned long len;
 
+	/* !!! length of the buffers. MTU is IP MTU, not PACLEN!  */
 
-static int sp_rebuild_header(struct sk_buff *skb)
-{
-#ifdef CONFIG_INET
-	return ax25_rebuild_header(skb);
-#else
-	return 0;
-#endif
-}
+	len = dev->mtu * 2;
 
+	rbuff = kmalloc(len + 4, GFP_KERNEL);
+	if (rbuff == NULL)
+		goto err_exit;
+
+	xbuff = kmalloc(len + 4, GFP_KERNEL);
+	if (xbuff == NULL)
+		goto err_exit;
 
-/* Open the low-level part of the 6pack channel. */
-static int sp_open(struct net_device *dev)
-{
-	struct sixpack *sp = (struct sixpack *) dev->priv;
-	unsigned long len;
+	spin_lock_bh(&sp->lock);
 
 	if (sp->tty == NULL)
 		return -ENODEV;
@@ -445,18 +536,8 @@
 	 * xbuff	Transmit buffer.
 	 */
 
-	/* !!! length of the buffers. MTU is IP MTU, not PACLEN!
-	 */
-
-	len = dev->mtu * 2;
-
-	if ((sp->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL)
-		return -ENOMEM;
-
-	if ((sp->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) {
-		kfree(sp->rbuff);
-		return -ENOMEM;
-	}
+	rbuff = xchg(&sp->rbuff, rbuff);
+	xbuff = xchg(&sp->xbuff, xbuff);
 
 	sp->mtu	     = AX25_MTU + 73;
 	sp->buffsize = len;
@@ -465,7 +546,7 @@
 	sp->rx_count_cooked = 0;
 	sp->xleft    = 0;
 
-	sp->flags   &= (1 << SIXPF_INUSE);      /* Clear ESCAPE & ERROR flags */
+	sp->flags	= 0;		/* Clear ESCAPE & ERROR flags */
 
 	sp->duplex = 0;
 	sp->tx_delay    = SIXP_TXDELAY;
@@ -482,49 +563,47 @@
 
 	init_timer(&sp->tx_t);
 	init_timer(&sp->resync_t);
-	return 0;
-}
 
+	spin_unlock_bh(&sp->lock);
 
-/* Close the low-level part of the 6pack channel. */
-static int sp_close(struct net_device *dev)
-{
-	struct sixpack *sp = (struct sixpack *) dev->priv;
-
-	if (sp->tty == NULL)
-		return -EBUSY;
+	err = 0;
 
-	sp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+err_exit:
+	if (xbuff)
+		kfree(xbuff);
+	if (rbuff)
+		kfree(rbuff);
 
-	netif_stop_queue(dev);
-	return 0;
+	return err;
 }
 
+
 static int sixpack_receive_room(struct tty_struct *tty)
 {
 	return 65536;  /* We can handle an infinite amount of data. :-) */
 }
 
-/* !!! receive state machine */
-
 /*
  * Handle the 'receiver data ready' interrupt.
  * This function is called by the 'tty_io' module in the kernel when
  * a block of 6pack data has been received, which can now be decapsulated
  * and sent on to some IP layer for further processing.
  */
-static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static void sixpack_receive_buf(struct tty_struct *tty,
+	const unsigned char *cp, char *fp, int count)
 {
+	struct sixpack *sp;
 	unsigned char buf[512];
 	int count1;
 
-	struct sixpack *sp = (struct sixpack *) tty->disc_data;
+	if (!count)
+		return;
 
-	if (!sp || sp->magic != SIXPACK_MAGIC ||
-	    !netif_running(sp->dev) || !count)
+	sp = sp_get(tty);
+	if (!sp)
 		return;
 
-	memcpy(buf, cp, count<sizeof(buf)? count:sizeof(buf));
+	memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
 
 	/* Read the characters out of the buffer */
 
@@ -538,6 +617,67 @@
 		}
 	}
 	sixpack_decode(sp, buf, count1);
+
+	sp_put(sp);
+	if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
+	    && tty->driver->unthrottle)
+		tty->driver->unthrottle(tty);
+}
+
+/*
+ * Try to resync the TNC. Called by the resync timer defined in
+ * decode_prio_command
+ */
+
+static void resync_tnc(unsigned long channel)
+{
+	struct sixpack *sp = (struct sixpack *) channel;
+	struct net_device *dev = sp->dev;
+	static char resync_cmd = 0xe8;
+
+	printk(KERN_INFO "%s: resyncing TNC\n", dev->name);
+
+	/* clear any data that might have been received */
+
+	sp->rx_count = 0;
+	sp->rx_count_cooked = 0;
+
+	/* reset state machine */
+
+	sp->status = 1;
+	sp->status1 = 1;
+	sp->status2 = 0;
+	sp->tnc_ok = 0;
+
+	/* resync the TNC */
+
+	sp->led_state = 0x60;
+	sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+	sp->tty->driver->write(sp->tty, 0, &resync_cmd, 1);
+
+
+	/* Start resync timer again -- the TNC might be still absent */
+
+	del_timer(&sp->resync_t);
+	sp->resync_t.data = (unsigned long) sp;
+	sp->resync_t.function = resync_tnc;
+	sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
+	add_timer(&sp->resync_t);
+}
+
+static inline int tnc_init(struct sixpack *sp)
+{
+	unsigned char inbyte = 0xe8;
+
+	sp->tty->driver->write(sp->tty, 0, &inbyte, 1);
+
+	del_timer(&sp->resync_t);
+	sp->resync_t.data = (unsigned long) sp;
+	sp->resync_t.function = resync_tnc;
+	sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
+	add_timer(&sp->resync_t);
+
+	return 0;
 }
 
 /*
@@ -549,37 +689,33 @@
  */
 static int sixpack_open(struct tty_struct *tty)
 {
-	struct sixpack *sp = (struct sixpack *) tty->disc_data;
-	int err;
+	struct sixpack *sp;
+	int err = 0;
 
-	/* First make sure we're not already connected. */
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
 
-	if (sp && sp->magic == SIXPACK_MAGIC)
-		return -EEXIST;
+	sp = sp_alloc();
+	if (!sp) {
+		err = -ENOMEM;
+		goto out;
+	}
 
-	/* OK.  Find a free 6pack channel to use. */
-	if ((sp = sp_alloc()) == NULL)
-		return -ENFILE;
 	sp->tty = tty;
-	tty->disc_data = sp;
-	if (tty->driver->flush_buffer)
-		tty->driver->flush_buffer(tty);
-
-	if (tty->ldisc.flush_buffer)
-		tty->ldisc.flush_buffer(tty);
-
-	/* Restore default settings */
-	sp->dev->type = ARPHRD_AX25;
+	atomic_set(&sp->refcnt, 1);
+	init_MUTEX_LOCKED(&sp->dead_sem);
 
 	/* Perform the low-level 6pack initialization. */
 	if ((err = sp_open(sp->dev)))
-		return err;
+		goto out;
 
 	/* Done.  We have linked the TTY line to a channel. */
+	tty->disc_data = sp;
 
 	tnc_init(sp);
 
-	return sp->dev->base_addr;
+out:
+	return err;
 }
 
 
@@ -593,102 +729,93 @@
 {
 	struct sixpack *sp = (struct sixpack *) tty->disc_data;
 
-	/* First make sure we're connected. */
-	if (!sp || sp->magic != SIXPACK_MAGIC)
+	write_lock(&disc_data_lock);
+	sp = tty->disc_data;
+	tty->disc_data = 0;
+	write_unlock(&disc_data_lock);
+	if (sp == 0)
 		return;
 
-	rtnl_lock();
-	dev_close(sp->dev);
+	/*
+	 * We have now ensured that nobody can start using ap from now on, but
+	 * we have to wait for all existing users to finish.
+	 */
+	if (!atomic_dec_and_test(&sp->refcnt))
+		down(&sp->dead_sem);
 
 	del_timer(&sp->tx_t);
 	del_timer(&sp->resync_t);
 
-	tty->disc_data = 0;
-	sp->tty = NULL;
-
 	sp_free(sp);
-	unregister_netdevice(sp->dev);
-	rtnl_unlock();
+	unregister_netdev(sp->dev);
 }
 
-
-static struct net_device_stats *sp_get_stats(struct net_device *dev)
-{
-	struct sixpack *sp = (struct sixpack *) dev->priv;
-	return &sp->stats;
-}
-
-
 static int sp_set_mac_address(struct net_device *dev, void *addr)
 {
 	return copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN) ? -EFAULT : 0;
 }
 
-static int sp_set_dev_mac_address(struct net_device *dev, void *addr)
-{
-	struct sockaddr *sa = addr;
-	memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);
-	return 0;
-}
-
-
 /* Perform I/O control on an active 6pack channel. */
-static int sixpack_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
+static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
+	unsigned int cmd, unsigned long arg)
 {
-	struct sixpack *sp = (struct sixpack *) tty->disc_data;
-	unsigned int tmp;
+	struct sixpack *sp = sp_get(tty);
+	unsigned int tmp, err;
 
-	/* First make sure we're connected. */
-	if (!sp || sp->magic != SIXPACK_MAGIC)
-		return -EINVAL;
+	if (!sp)
+		return -ENXIO;
 
 	switch(cmd) {
 	case SIOCGIFNAME:
-		return copy_to_user(arg, sp->dev->name, strlen(sp->dev->name) + 1) ? -EFAULT : 0;
+		err = copy_to_user((void *) arg, sp->dev->name,
+		                   strlen(sp->dev->name) + 1) ? -EFAULT : 0;
+		break;
 
 	case SIOCGIFENCAP:
-		return put_user(0, (int *)arg);
+		err = put_user(0, (int *)arg);
+		break;
 
 	case SIOCSIFENCAP:
-		if (get_user(tmp, (int *) arg))
-			return -EFAULT;
+		if (get_user(tmp, (int *) arg)) {
+			err = -EFAULT;
+			break;
+		}
 
 		sp->mode = tmp;
 		sp->dev->addr_len        = AX25_ADDR_LEN;	  /* sizeof an AX.25 addr */
 		sp->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3;
 		sp->dev->type            = ARPHRD_AX25;
 
-		return 0;
+		err = 0;
+		break;
 
 	 case SIOCSIFHWADDR:
-		return sp_set_mac_address(sp->dev, arg);
+		err = sp_set_mac_address(sp->dev, (void *) arg);
+		break;
 
 	/* Allow stty to read, but not set, the serial port */
 	case TCGETS:
 	case TCGETA:
-		return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
+		err = n_tty_ioctl(tty, (struct file *) file, cmd, arg);
+		break;
 
 	default:
 		return -ENOIOCTLCMD;
 	}
-}
 
-static int sp_open_dev(struct net_device *dev)
-{
-	struct sixpack *sp = (struct sixpack *) dev->priv;
-	if (sp->tty == NULL)
-		return -ENODEV;
-	return 0;
+	sp_put(sp);
+
+	return err;
 }
 
 /* Fill in our line protocol discipline */
 static struct tty_ldisc sp_ldisc = {
-	.magic	= TTY_LDISC_MAGIC,
+	.owner		= THIS_MODULE,
+	.magic		= TTY_LDISC_MAGIC,
 	.name		= "6pack",
 	.open		= sixpack_open,
-	.close	= sixpack_close,
-	.ioctl	= (int (*)(struct tty_struct *, struct file *,
-			unsigned int, unsigned long)) sixpack_ioctl,
+	.close		= sixpack_close,
+	.ioctl		= sixpack_ioctl,
 	.receive_buf	= sixpack_receive_buf,
 	.receive_room	= sixpack_receive_room,
 	.write_wakeup	= sixpack_write_wakeup,
@@ -696,34 +823,18 @@
 
 /* Initialize 6pack control device -- register 6pack line discipline */
 
-static char msg_banner[]  __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n";
-static char msg_nomem[]   __initdata = KERN_ERR  "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n";
+static char msg_banner[]  __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION "\n";
 static char msg_regfail[] __initdata = KERN_ERR  "6pack: can't register line discipline (err = %d)\n";
 
 static int __init sixpack_init_driver(void)
 {
 	int status;
 
-	/* Do sanity checks on maximum device parameter. */
-	if (sixpack_maxdev < 4)
-		sixpack_maxdev = 4;
-
-	printk(msg_banner, sixpack_maxdev);
-
-	sixpack_ctrls = (sixpack_ctrl_t **) kmalloc(sizeof(void*)*sixpack_maxdev, GFP_KERNEL);
-	if (sixpack_ctrls == NULL) {
-		printk(msg_nomem);
-		return -ENOMEM;
-	}
-
-	/* Clear the pointer array, we allocate devices when we need them */
-	memset(sixpack_ctrls, 0, sizeof(void*)*sixpack_maxdev); /* Pointers */
+	printk(msg_banner);
 
 	/* Register the provided line protocol discipline */
-	if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0) {
+	if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0)
 		printk(msg_regfail, status);
-		kfree(sixpack_ctrls);
-	}
 
 	return status;
 }
@@ -732,36 +843,16 @@
 
 static void __exit sixpack_exit_driver(void)
 {
-	int i;
-
-	if ((i = tty_register_ldisc(N_6PACK, NULL)))
-		printk(msg_unregfail, i);
+	int ret;
 
-	for (i = 0; i < sixpack_maxdev; i++) {
-		if (sixpack_ctrls[i]) {
-			/*
-			* VSV = if dev->start==0, then device
-			* unregistered while close proc.
-			*/
-			if (netif_running(&sixpack_ctrls[i]->dev))
-				 unregister_netdev(&sixpack_ctrls[i]->dev);
-
-			kfree(sixpack_ctrls[i]);
-		}
-	}
-	kfree(sixpack_ctrls);
+	if ((ret = tty_register_ldisc(N_6PACK, NULL)))
+		printk(msg_unregfail, ret);
 }
 
-
 /* Initialize the 6pack driver.  Called by DDI. */
 static int sixpack_init(struct net_device *dev)
 {
-	struct sixpack *sp = (struct sixpack *) dev->priv;
-
-	static char ax25_bcast[AX25_ADDR_LEN] =
-		{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
-	static char ax25_test[AX25_ADDR_LEN] =
-		{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
+	struct sixpack *sp = netdev_priv(dev);
 
 	if (sp == NULL)		/* Allocation failed ?? */
 		return -ENODEV;
@@ -769,52 +860,15 @@
 	/* Set up the "6pack Control Block". (And clear statistics) */
 
 	memset(sp, 0, sizeof (struct sixpack));
-	sp->magic  = SIXPACK_MAGIC;
 	sp->dev	   = dev;
 
-	/* Finish setting up the DEVICE info. */
-	dev->mtu		= SIXP_MTU;
-	dev->hard_start_xmit	= sp_xmit;
-	dev->open		= sp_open_dev;
-	dev->stop		= sp_close;
-	dev->hard_header	= sp_header;
-	dev->get_stats	        = sp_get_stats;
-	dev->set_mac_address    = sp_set_dev_mac_address;
-	dev->hard_header_len	= AX25_MAX_HEADER_LEN;
-	dev->addr_len		= AX25_ADDR_LEN;
-	dev->type		= ARPHRD_AX25;
-	dev->tx_queue_len	= 10;
-	dev->rebuild_header	= sp_rebuild_header;
-	dev->tx_timeout		= NULL;
-
-	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);	/* Only activated in AX.25 mode */
-	memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);	/*    ""      ""       ""    "" */
-
-	/* New-style flags. */
-	dev->flags		= 0;
-
 	return 0;
 }
 
-
-
-
-/* ----> 6pack timer interrupt handler and friends. <---- */
-static void sp_start_tx_timer(struct sixpack *sp)
-{
-	int when = sp->slottime;
-
-	del_timer(&sp->tx_t);
-	sp->tx_t.data = (unsigned long) sp;
-	sp->tx_t.function = sp_xmit_on_air;
-	sp->tx_t.expires = jiffies + ((when+1)*HZ)/100;
-	add_timer(&sp->tx_t);
-}
-
-
 /* encode an AX.25 packet into 6pack */
 
-static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, int length, unsigned char tx_delay)
+static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw,
+	int length, unsigned char tx_delay)
 {
 	int count = 0;
 	unsigned char checksum = 0, buf[400];
@@ -849,47 +903,28 @@
 	return raw_count;
 }
 
+/* decode 4 sixpack-encoded bytes into 3 data bytes */
 
-/* decode a 6pack packet */
-
-static void
-sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count)
-{
-	unsigned char inbyte;
-	int count1;
-
-	for (count1 = 0; count1 < count; count1++) {
-		inbyte = pre_rbuff[count1];
-		if (inbyte == SIXP_FOUND_TNC) {
-			printk(KERN_INFO "6pack: TNC found.\n");
-			sp->tnc_ok = 1;
-			del_timer(&sp->resync_t);
-		}
-		if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
-			decode_prio_command(inbyte, sp);
-		else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
-			decode_std_command(inbyte, sp);
-		else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)
-			decode_data(inbyte, sp);
-	}
-}
-
-static int tnc_init(struct sixpack *sp)
+static void decode_data(unsigned char inbyte, struct sixpack *sp)
 {
-	unsigned char inbyte = 0xe8;
+	unsigned char *buf;
 
-	sp->tty->driver->write(sp->tty, 0, &inbyte, 1);
+	if (sp->rx_count != 3) {
+		sp->raw_buf[sp->rx_count++] = inbyte;
 
-	del_timer(&sp->resync_t);
-	sp->resync_t.data = (unsigned long) sp;
-	sp->resync_t.function = resync_tnc;
-	sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
-	add_timer(&sp->resync_t);
+		return;
+	}
 
-	return 0;
+	buf = sp->raw_buf;
+	sp->cooked_buf[sp->rx_count_cooked++] =
+		buf[0] | ((buf[1] << 2) & 0xc0);
+	sp->cooked_buf[sp->rx_count_cooked++] =
+		(buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
+	sp->cooked_buf[sp->rx_count_cooked++] =
+		(buf[2] & 0x03) | (inbyte << 2);
+	sp->rx_count = 0;
 }
 
-
 /* identify and execute a 6pack priority command byte */
 
 static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
@@ -916,8 +951,7 @@
 				cmd &= !SIXP_RX_DCD_MASK;
 		}
 		sp->status = cmd & SIXP_PRIO_DATA_MASK;
-	}
-	else { /* output watchdog char if idle */
+	} else { /* output watchdog char if idle */
 		if ((sp->status2 != 0) && (sp->duplex == 1)) {
 			sp->led_state = 0x70;
 			sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
@@ -948,46 +982,6 @@
 	sp->status1 = cmd & SIXP_PRIO_DATA_MASK;
 }
 
-/* try to resync the TNC. Called by the resync timer defined in
-  decode_prio_command */
-
-static void resync_tnc(unsigned long channel)
-{
-	static char resync_cmd = 0xe8;
-	struct sixpack *sp = (struct sixpack *) channel;
-
-	printk(KERN_INFO "6pack: resyncing TNC\n");
-
-	/* clear any data that might have been received */
-
-	sp->rx_count = 0;
-	sp->rx_count_cooked = 0;
-
-	/* reset state machine */
-
-	sp->status = 1;
-	sp->status1 = 1;
-	sp->status2 = 0;
-	sp->tnc_ok = 0;
-
-	/* resync the TNC */
-
-	sp->led_state = 0x60;
-	sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
-	sp->tty->driver->write(sp->tty, 0, &resync_cmd, 1);
-
-
-	/* Start resync timer again -- the TNC might be still absent */
-
-	del_timer(&sp->resync_t);
-	sp->resync_t.data = (unsigned long) sp;
-	sp->resync_t.function = resync_tnc;
-	sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
-	add_timer(&sp->resync_t);
-}
-
-
-
 /* identify and execute a standard 6pack command byte */
 
 static void decode_std_command(unsigned char cmd, struct sixpack *sp)
@@ -997,67 +991,70 @@
 
 	channel = cmd & SIXP_CHN_MASK;
 	switch (cmd & SIXP_CMD_MASK) {     /* normal command */
-		case SIXP_SEOF:
-			if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) {
-				if ((sp->status & SIXP_RX_DCD_MASK) ==
-					SIXP_RX_DCD_MASK) {
-					sp->led_state = 0x68;
-					sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
-				}
-			} else {
-				sp->led_state = 0x60;
-				/* fill trailing bytes with zeroes */
+	case SIXP_SEOF:
+		if ((sp->rx_count == 0) && (sp->rx_count_cooked == 0)) {
+			if ((sp->status & SIXP_RX_DCD_MASK) ==
+				SIXP_RX_DCD_MASK) {
+				sp->led_state = 0x68;
 				sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
-				rest = sp->rx_count;
-				if (rest != 0)
-					 for (i = rest; i <= 3; i++)
-						decode_data(0, sp);
-				if (rest == 2)
-					sp->rx_count_cooked -= 2;
-				else if (rest == 3)
-					sp->rx_count_cooked -= 1;
-				for (i = 0; i < sp->rx_count_cooked; i++)
-					checksum += sp->cooked_buf[i];
-				if (checksum != SIXP_CHKSUM) {
-					printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum);
-				} else {
-					sp->rcount = sp->rx_count_cooked-2;
-					sp_bump(sp, 0);
-				}
-				sp->rx_count_cooked = 0;
 			}
-			break;
-		case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n");
-			break;
-		case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n");
-			break;
-		case SIXP_RX_BUF_OVL:
-			printk(KERN_DEBUG "6pack: RX buffer overflow\n");
+		} else {
+			sp->led_state = 0x60;
+			/* fill trailing bytes with zeroes */
+			sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
+			rest = sp->rx_count;
+			if (rest != 0)
+				 for (i = rest; i <= 3; i++)
+					decode_data(0, sp);
+			if (rest == 2)
+				sp->rx_count_cooked -= 2;
+			else if (rest == 3)
+				sp->rx_count_cooked -= 1;
+			for (i = 0; i < sp->rx_count_cooked; i++)
+				checksum += sp->cooked_buf[i];
+			if (checksum != SIXP_CHKSUM) {
+				printk(KERN_DEBUG "6pack: bad checksum %2.2x\n", checksum);
+			} else {
+				sp->rcount = sp->rx_count_cooked-2;
+				sp_bump(sp, 0);
+			}
+			sp->rx_count_cooked = 0;
+		}
+		break;
+	case SIXP_TX_URUN: printk(KERN_DEBUG "6pack: TX underrun\n");
+		break;
+	case SIXP_RX_ORUN: printk(KERN_DEBUG "6pack: RX overrun\n");
+		break;
+	case SIXP_RX_BUF_OVL:
+		printk(KERN_DEBUG "6pack: RX buffer overflow\n");
 	}
 }
 
-/* decode 4 sixpack-encoded bytes into 3 data bytes */
+/* decode a 6pack packet */
 
-static void decode_data(unsigned char inbyte, struct sixpack *sp)
+static void
+sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count)
 {
-	unsigned char *buf;
+	unsigned char inbyte;
+	int count1;
 
-	if (sp->rx_count != 3)
-		sp->raw_buf[sp->rx_count++] = inbyte;
-	else {
-		buf = sp->raw_buf;
-		sp->cooked_buf[sp->rx_count_cooked++] =
-			buf[0] | ((buf[1] << 2) & 0xc0);
-		sp->cooked_buf[sp->rx_count_cooked++] =
-			(buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
-		sp->cooked_buf[sp->rx_count_cooked++] =
-			(buf[2] & 0x03) | (inbyte << 2);
-		sp->rx_count = 0;
+	for (count1 = 0; count1 < count; count1++) {
+		inbyte = pre_rbuff[count1];
+		if (inbyte == SIXP_FOUND_TNC) {
+			printk(KERN_INFO "6pack: TNC found.\n");
+			sp->tnc_ok = 1;
+			del_timer(&sp->resync_t);
+		}
+		if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
+			decode_prio_command(inbyte, sp);
+		else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
+			decode_std_command(inbyte, sp);
+		else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)
+			decode_data(inbyte, sp);
 	}
 }
 
-
-MODULE_AUTHOR("Andreas Könsgen <ajk@ccac.rwth-aachen.de>");
+MODULE_AUTHOR("Ralf Baechle DO1GRB <ralf@linux-mips.org>");
 MODULE_DESCRIPTION("6pack driver for AX.25");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_LDISC(N_6PACK);
diff -Nru a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
--- a/drivers/net/hamradio/baycom_epp.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/hamradio/baycom_epp.c	Sat Apr  3 19:38:56 2004
@@ -646,7 +646,7 @@
 
 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 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 @@
 	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 @@
 	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 @@
 	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 @@
         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 @@
 	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 @@
 	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 @@
 	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 @@
 	/*
 	 * 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 @@
 
 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 @@
 		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 -Nru a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
--- a/drivers/net/hamradio/baycom_par.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/hamradio/baycom_par.c	Sat Apr  3 19:38:56 2004
@@ -272,7 +272,7 @@
 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_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 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_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 @@
 		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 @@
 		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 -Nru a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
--- a/drivers/net/hamradio/baycom_ser_fdx.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/hamradio/baycom_ser_fdx.c	Sat Apr  3 19:38:44 2004
@@ -281,7 +281,7 @@
 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 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_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 @@
 		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 @@
 		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 -Nru a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
--- a/drivers/net/hamradio/baycom_ser_hdx.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/hamradio/baycom_ser_hdx.c	Sat Apr  3 19:38:41 2004
@@ -375,7 +375,7 @@
 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 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_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 @@
 		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 @@
 		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 -Nru a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
--- a/drivers/net/hamradio/hdlcdrv.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/hamradio/hdlcdrv.c	Sat Apr  3 19:38:54 2004
@@ -737,7 +737,7 @@
 	static const struct hdlcdrv_channel_params dflt_ch_params = { 
 		20, 2, 10, 40, 0 
 	};
-	struct hdlcdrv_state *s = dev->priv;;
+	struct hdlcdrv_state *s = dev->priv;
 
 	/*
 	 * initialize the hdlcdrv_state struct
diff -Nru a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
--- a/drivers/net/hp-plus.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/hp-plus.c	Sat Apr  3 19:38:41 2004
@@ -236,6 +236,9 @@
 
 	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 -Nru a/drivers/net/hp.c b/drivers/net/hp.c
--- a/drivers/net/hp.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/hp.c	Sat Apr  3 19:38:42 2004
@@ -207,6 +207,9 @@
 	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 -Nru a/drivers/net/hplance.c b/drivers/net/hplance.c
--- a/drivers/net/hplance.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/hplance.c	Sat Apr  3 19:38:43 2004
@@ -63,7 +63,7 @@
 
 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 @@
 		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 @@
                 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 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_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 -Nru a/drivers/net/hydra.c b/drivers/net/hydra.c
--- a/drivers/net/hydra.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/hydra.c	Sat Apr  3 19:38:43 2004
@@ -142,6 +142,10 @@
     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 -Nru a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
--- a/drivers/net/ibmveth.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/ibmveth.c	Sat Apr  3 19:38:40 2004
@@ -40,6 +40,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -404,27 +405,27 @@
 static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
 {
 	if(adapter->buffer_list_addr != NULL) {
-		if(adapter->buffer_list_dma != NO_TCE) {
+		if(!vio_dma_mapping_error(adapter->buffer_list_dma)) {
 			vio_unmap_single(adapter->vdev, adapter->buffer_list_dma, 4096, PCI_DMA_BIDIRECTIONAL);
-			adapter->buffer_list_dma = NO_TCE;
+			adapter->buffer_list_dma = DMA_ERROR_CODE;
 		}
 		free_page((unsigned long)adapter->buffer_list_addr);
 		adapter->buffer_list_addr = NULL;
 	} 
 
 	if(adapter->filter_list_addr != NULL) {
-		if(adapter->filter_list_dma != NO_TCE) {
+		if(!vio_dma_mapping_error(adapter->filter_list_dma)) {
 			vio_unmap_single(adapter->vdev, adapter->filter_list_dma, 4096, PCI_DMA_BIDIRECTIONAL);
-			adapter->filter_list_dma = NO_TCE;
+			adapter->filter_list_dma = DMA_ERROR_CODE;
 		}
 		free_page((unsigned long)adapter->filter_list_addr);
 		adapter->filter_list_addr = NULL;
 	}
 
 	if(adapter->rx_queue.queue_addr != NULL) {
-		if(adapter->rx_queue.queue_dma != NO_TCE) {
+		if(!vio_dma_mapping_error(adapter->rx_queue.queue_dma)) {
 			vio_unmap_single(adapter->vdev, adapter->rx_queue.queue_dma, adapter->rx_queue.queue_len, PCI_DMA_BIDIRECTIONAL);
-			adapter->rx_queue.queue_dma = NO_TCE;
+			adapter->rx_queue.queue_dma = DMA_ERROR_CODE;
 		}
 		kfree(adapter->rx_queue.queue_addr);
 		adapter->rx_queue.queue_addr = NULL;
@@ -473,9 +474,9 @@
 	adapter->filter_list_dma = vio_map_single(adapter->vdev, adapter->filter_list_addr, 4096, PCI_DMA_BIDIRECTIONAL);
 	adapter->rx_queue.queue_dma = vio_map_single(adapter->vdev, adapter->rx_queue.queue_addr, adapter->rx_queue.queue_len, PCI_DMA_BIDIRECTIONAL);
 
-	if((adapter->buffer_list_dma == NO_TCE) || 
-	   (adapter->filter_list_dma == NO_TCE) || 
-	   (adapter->rx_queue.queue_dma == NO_TCE)) {
+	if((vio_dma_mapping_error(adapter->buffer_list_dma) ) ||
+	   (vio_dma_mapping_error(adapter->filter_list_dma)) ||
+	   (vio_dma_mapping_error(adapter->rx_queue.queue_dma))) {
 		ibmveth_error_printk("unable to map filter or buffer list pages\n");
 		ibmveth_cleanup(adapter);
 		return -ENOMEM;
@@ -527,7 +528,10 @@
 	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 +560,9 @@
 	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 +623,8 @@
 	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++;
@@ -637,7 +645,7 @@
 	desc[0].fields.address = vio_map_single(adapter->vdev, skb->data, desc[0].fields.length, PCI_DMA_TODEVICE);
 	desc[0].fields.valid   = 1;
 
-	if(desc[0].fields.address == NO_TCE) {
+	if(vio_dma_mapping_error(desc[0].fields.address)) {
 		ibmveth_error_printk("tx: unable to map initial fragment\n");
 		adapter->tx_map_failed++;
 		adapter->stats.tx_dropped++;
@@ -656,7 +664,7 @@
 		desc[curfrag+1].fields.length = frag->size;
 		desc[curfrag+1].fields.valid  = 1;
 
-		if(desc[curfrag+1].fields.address == NO_TCE) {
+		if(vio_dma_mapping_error(desc[curfrag+1].fields.address)) {
 			ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag);
 			adapter->tx_map_failed++;
 			adapter->stats.tx_dropped++;
@@ -674,8 +682,8 @@
 	}
 
 	/* 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,
@@ -937,9 +945,9 @@
 
 	INIT_WORK(&adapter->replenish_task, (void*)ibmveth_replenish_task, (void*)adapter);
 
-	adapter->buffer_list_dma = NO_TCE;
-	adapter->filter_list_dma = NO_TCE;
-	adapter->rx_queue.queue_dma = NO_TCE;
+	adapter->buffer_list_dma = DMA_ERROR_CODE;
+	adapter->filter_list_dma = DMA_ERROR_CODE;
+	adapter->rx_queue.queue_dma = DMA_ERROR_CODE;
 
 	atomic_set(&adapter->not_replenishing, 1);
 
diff -Nru a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
--- a/drivers/net/irda/vlsi_ir.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/irda/vlsi_ir.c	Sat Apr  3 19:38:41 2004
@@ -173,7 +173,7 @@
 			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 @@
 			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 @@
 	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 @@
 				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 @@
 				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 @@
 	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 @@
 		}
 	}
 
-	/* 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 @@
 	 * 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 @@
 		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 -Nru a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
--- a/drivers/net/isa-skeleton.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/isa-skeleton.c	Sat Apr  3 19:38:56 2004
@@ -303,7 +303,7 @@
 	}
 #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 @@
 
 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 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 @@
  */
 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 @@
  */
 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 @@
 
 	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 @@
 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 @@
 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 @@
  */
 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 -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
--- a/drivers/net/lasi_82596.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/lasi_82596.c	Sat Apr  3 19:38:41 2004
@@ -426,7 +426,7 @@
 
 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 = dev->priv;
 
 	u32 v = (u32) (c) | (u32) (x);
 	u16 a, b;
@@ -481,7 +481,7 @@
 
 static void i596_display_data(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	struct i596_cmd *cmd;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -541,7 +541,7 @@
 
 static inline void init_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = dev->priv;
 	int i;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
@@ -595,7 +595,7 @@
 
 static inline void remove_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = dev->priv;
 	struct i596_rbd *rbd;
 	int i;
 
@@ -612,7 +612,7 @@
 
 static void rebuild_rx_bufs(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	int i;
 
 	/* Ensure rx frame/buffer descriptors are tidy */
@@ -633,7 +633,7 @@
 
 static int init_i596_mem(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	unsigned long flags;
 
 	disable_irq(dev->irq);	/* disable IRQs from LAN */
@@ -727,7 +727,7 @@
 
 static inline int i596_rx(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_private *lp = dev->priv;
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 	int frames = 0;
@@ -802,9 +802,10 @@
 				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 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 = dev->priv;
 	unsigned long flags;
 
 	DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head));
@@ -987,7 +988,7 @@
    device list */
 static int i596_test(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	volatile int *tint;
 	u32 data;
 
@@ -1041,7 +1042,7 @@
 
 static void i596_tx_timeout (struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 
 	/* Transmitter timeout, serious problems. */
 	DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
@@ -1070,7 +1071,7 @@
 
 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 = dev->priv;
 	struct tx_cmd *tx_cmd;
 	struct i596_tbd *tbd;
 	short length = skb->len;
@@ -1219,7 +1220,7 @@
 
 	dev->priv = (void *)(dev->mem_start);
 
-	lp = (struct i596_private *) dev->priv;
+	lp = dev->priv;
 	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 @@
 		return IRQ_NONE;
 	}
 
-	lp = (struct i596_private *) dev->priv;
+	lp = dev->priv;
 
 	spin_lock (&lp->lock);
 
@@ -1395,7 +1396,7 @@
 
 static int i596_close(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	unsigned long flags;
 
 	netif_stop_queue(dev);
@@ -1429,7 +1430,7 @@
 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 = dev->priv;
 
 	return &lp->stats;
 }
@@ -1440,7 +1441,7 @@
 
 static void set_multicast_list(struct net_device *dev)
 {
-	struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_private *lp = dev->priv;
 	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"));
@@ -1594,7 +1595,7 @@
 		
 		unregister_netdev(netdevice);
 
-		lp = (struct i596_private *) netdevice->priv;
+		lp = netdevice->priv;
 		dma_free_noncoherent(lp->dev, sizeof(struct i596_private), 
 				       (void *)netdevice->mem_start, lp->dma_addr);
 		free_netdev(netdevice);
diff -Nru a/drivers/net/lne390.c b/drivers/net/lne390.c
--- a/drivers/net/lne390.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/lne390.c	Sat Apr  3 19:38:55 2004
@@ -299,6 +299,9 @@
 
 	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 -Nru a/drivers/net/loopback.c b/drivers/net/loopback.c
--- a/drivers/net/loopback.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/loopback.c	Sat Apr  3 19:38:41 2004
@@ -123,7 +123,7 @@
  */
 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 = dev->priv;
 
 	skb_orphan(skb);
 
diff -Nru a/drivers/net/mac8390.c b/drivers/net/mac8390.c
--- a/drivers/net/mac8390.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/mac8390.c	Sat Apr  3 19:38:43 2004
@@ -442,6 +442,9 @@
 	/* 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 -Nru a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
--- a/drivers/net/mac89x0.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/mac89x0.c	Sat Apr  3 19:38:43 2004
@@ -225,7 +225,7 @@
 		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 @@
 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 @@
 	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 @@
 	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 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 @@
 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 @@
 
 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 -Nru a/drivers/net/mace.c b/drivers/net/mace.c
--- a/drivers/net/mace.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/mace.c	Sat Apr  3 19:38:42 2004
@@ -202,7 +202,7 @@
 		rc = -ENOMEM;
 		goto err_unmap_tx_dma;
 	}
-	mp->rx_dma_intr = macio_irq(mdev, 2);;
+	mp->rx_dma_intr = macio_irq(mdev, 2);
 
 	mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
 	mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
diff -Nru a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
--- a/drivers/net/myri_sbus.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/myri_sbus.c	Sat Apr  3 19:38:41 2004
@@ -435,9 +435,9 @@
 
 		/* 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 @@
 			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 @@
 
 			/* 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 -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c
--- a/drivers/net/natsemi.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/natsemi.c	Sat Apr  3 19:38:41 2004
@@ -175,6 +175,8 @@
 #define DRV_VERSION	"1.07+LK1.0.17"
 #define DRV_RELDATE	"Sep 27, 2002"
 
+#define RX_OFFSET	2
+
 /* Updated to recommendations in pci-skeleton v2.03. */
 
 /* The user-configurable values.
@@ -1467,13 +1469,14 @@
 		struct sk_buff *skb;
 		int entry = np->dirty_rx % RX_RING_SIZE;
 		if (np->rx_skbuff[entry] == NULL) {
-			skb = dev_alloc_skb(np->rx_buf_sz);
+			unsigned int buflen = np->rx_buf_sz + RX_OFFSET;
+			skb = dev_alloc_skb(buflen);
 			np->rx_skbuff[entry] = skb;
 			if (skb == NULL)
 				break; /* Better luck next round. */
 			skb->dev = dev; /* Mark as being used by this device. */
 			np->rx_dma[entry] = pci_map_single(np->pci_dev,
-				skb->data, skb->len, PCI_DMA_FROMDEVICE);
+				skb->tail, buflen, PCI_DMA_FROMDEVICE);
 			np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
 		}
 		np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz);
@@ -1543,6 +1546,7 @@
 static void drain_ring(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
+	unsigned int buflen = np->rx_buf_sz + RX_OFFSET;
 	int i;
 
 	/* Free all the skbuffs in the Rx queue. */
@@ -1551,7 +1555,7 @@
 		np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
 		if (np->rx_skbuff[i]) {
 			pci_unmap_single(np->pci_dev,
-				np->rx_dma[i], np->rx_skbuff[i]->len,
+				np->rx_dma[i], buflen,
 				PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(np->rx_skbuff[i]);
 		}
@@ -1747,6 +1751,7 @@
 	int entry = np->cur_rx % RX_RING_SIZE;
 	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 	s32 desc_status = le32_to_cpu(np->rx_head_desc->cmd_status);
+	unsigned int buflen = np->rx_buf_sz + RX_OFFSET;
 
 	/* If the driver owns the next entry it's a new packet. Send it up. */
 	while (desc_status < 0) { /* e.g. & DescOwn */
@@ -1785,13 +1790,13 @@
 			/* Check if the packet is long enough to accept
 			 * without copying to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
-			    && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+			    && (skb = dev_alloc_skb(pkt_len + RX_OFFSET)) != NULL) {
 				skb->dev = dev;
 				/* 16 byte align the IP header */
-				skb_reserve(skb, 2);
-				pci_dma_sync_single(np->pci_dev,
+				skb_reserve(skb, RX_OFFSET);
+				pci_dma_sync_single_for_cpu(np->pci_dev,
 					np->rx_dma[entry],
-					np->rx_skbuff[entry]->len,
+					buflen,
 					PCI_DMA_FROMDEVICE);
 #if HAS_IP_COPYSUM
 				eth_copy_and_sum(skb,
@@ -1801,10 +1806,13 @@
 				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],
+					buflen,
+					PCI_DMA_FROMDEVICE);
 			} else {
 				pci_unmap_single(np->pci_dev, np->rx_dma[entry],
-					np->rx_skbuff[entry]->len,
-					PCI_DMA_FROMDEVICE);
+					buflen, PCI_DMA_FROMDEVICE);
 				skb_put(skb = np->rx_skbuff[entry], pkt_len);
 				np->rx_skbuff[entry] = NULL;
 			}
diff -Nru a/drivers/net/ne.c b/drivers/net/ne.c
--- a/drivers/net/ne.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/ne.c	Sat Apr  3 19:38:43 2004
@@ -498,6 +498,9 @@
 	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 -Nru a/drivers/net/ne2.c b/drivers/net/ne2.c
--- a/drivers/net/ne2.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/ne2.c	Sat Apr  3 19:38:56 2004
@@ -509,6 +509,9 @@
 	
 	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 -Nru a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
--- a/drivers/net/ne2k-pci.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/ne2k-pci.c	Sat Apr  3 19:38:42 2004
@@ -359,6 +359,9 @@
 	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 -Nru a/drivers/net/ne2k_cbus.c b/drivers/net/ne2k_cbus.c
--- a/drivers/net/ne2k_cbus.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/ne2k_cbus.c	Sat Apr  3 19:38:42 2004
@@ -534,6 +534,9 @@
 	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 -Nru a/drivers/net/ne3210.c b/drivers/net/ne3210.c
--- a/drivers/net/ne3210.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/ne3210.c	Sat Apr  3 19:38:43 2004
@@ -205,6 +205,9 @@
 
 	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 -Nru a/drivers/net/netconsole.c b/drivers/net/netconsole.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/netconsole.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/net/ni5010.c b/drivers/net/ni5010.c
--- a/drivers/net/ni5010.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/ni5010.c	Sat Apr  3 19:38:43 2004
@@ -309,7 +309,7 @@
 	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 @@
 	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 @@
 /* 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 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 @@
    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 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 -Nru a/drivers/net/oaknet.c b/drivers/net/oaknet.c
--- a/drivers/net/oaknet.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/oaknet.c	Sat Apr  3 19:38:54 2004
@@ -192,6 +192,9 @@
 
 	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 -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
--- a/drivers/net/pcmcia/3c574_cs.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/pcmcia/3c574_cs.c	Sat Apr  3 19:38:42 2004
@@ -283,7 +283,7 @@
 	dev = alloc_etherdev(sizeof(struct el3_private));
 	if (!dev)
 		return NULL;
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 	link = &lp->link;
 	link->priv = dev;
 
@@ -388,7 +388,7 @@
 {
 	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];
@@ -733,7 +733,7 @@
 /* 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 +814,7 @@
 
 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 +837,7 @@
 
 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 +852,7 @@
 
 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 +877,7 @@
 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 +909,7 @@
 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 +1002,7 @@
 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 +1074,7 @@
 
 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 +1091,7 @@
  */
 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 +1128,7 @@
 
 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 +1190,7 @@
 /* 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 +1259,7 @@
 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 -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
--- a/drivers/net/pcmcia/3c589_cs.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/pcmcia/3c589_cs.c	Sat Apr  3 19:38:56 2004
@@ -196,7 +196,7 @@
     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,7 +304,7 @@
 {
     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;
@@ -526,7 +526,7 @@
 */
 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 +648,7 @@
 
 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 +672,7 @@
 
 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 +687,7 @@
 
 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 +741,7 @@
 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 +826,7 @@
 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 +906,7 @@
 
 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 +928,7 @@
 */
 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 +955,7 @@
 
 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 +1009,7 @@
 
 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 +1024,7 @@
 
 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 -Nru a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
--- a/drivers/net/pcmcia/com20020_cs.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/pcmcia/com20020_cs.c	Sat Apr  3 19:38:43 2004
@@ -492,7 +492,7 @@
             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 = dev->priv;
 		ARCRESET;
             }
         }
diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
--- a/drivers/net/pcmcia/fmvj18x_cs.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/pcmcia/fmvj18x_cs.c	Sat Apr  3 19:38:45 2004
@@ -256,7 +256,7 @@
     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 @@
 {
     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];
@@ -803,7 +803,7 @@
 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 +862,7 @@
 
 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 +892,7 @@
 
 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 +966,7 @@
 
 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 +1052,7 @@
 
 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 +1181,7 @@
 
 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 +1206,7 @@
 
 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 +1239,7 @@
 
 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 +1252,7 @@
 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 -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
--- a/drivers/net/pcmcia/ibmtr_cs.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/pcmcia/ibmtr_cs.c	Sat Apr  3 19:38:43 2004
@@ -178,7 +178,7 @@
 
     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 @@
 	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 @@
     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;
@@ -412,7 +412,7 @@
     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 -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
--- a/drivers/net/pcmcia/pcnet_cs.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/pcmcia/pcnet_cs.c	Sat Apr  3 19:38:55 2004
@@ -722,6 +722,10 @@
     link->dev = &info->node;
     link->state &= ~DEV_CONFIG_PENDING;
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+    dev->poll_controller = ei_poll;
+#endif
+
     if (register_netdev(dev) != 0) {
 	printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
 	link->dev = NULL;
diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
--- a/drivers/net/pcmcia/smc91c92_cs.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/pcmcia/smc91c92_cs.c	Sat Apr  3 19:38:45 2004
@@ -327,7 +327,7 @@
     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 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_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 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,7 +894,7 @@
 {
     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];
@@ -1069,7 +1069,7 @@
     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 +1091,7 @@
 {
     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 +1240,7 @@
 
 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 +1277,7 @@
 
 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 +1314,7 @@
 
 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 +1379,7 @@
 
 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 +1394,7 @@
 
 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 +1460,7 @@
 
 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 +1504,7 @@
 
 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 +1539,7 @@
 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 +1657,7 @@
 
 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 +1725,7 @@
 
 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 +1765,7 @@
 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 +1804,7 @@
 
 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 +1830,7 @@
 */
 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 +1855,7 @@
 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 +1930,7 @@
 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 +2044,7 @@
 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 +2109,7 @@
 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 +2202,7 @@
 
 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 -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
--- a/drivers/net/pcmcia/xirc2ps_cs.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/pcmcia/xirc2ps_cs.c	Sat Apr  3 19:38:43 2004
@@ -1666,6 +1666,7 @@
 			       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 -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
--- a/drivers/net/pcnet32.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/pcnet32.c	Sat Apr  3 19:38:42 2004
@@ -51,6 +51,7 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/irq.h>
 
 /*
  * PCI device identifiers for "new style" Linux PCI Device Drivers
@@ -225,10 +226,12 @@
  * 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 +482,14 @@
     .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 +1117,10 @@
     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 +1748,17 @@
 		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 -Nru a/drivers/net/plip.c b/drivers/net/plip.c
--- a/drivers/net/plip.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/plip.c	Sat Apr  3 19:38:56 2004
@@ -280,7 +280,7 @@
 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 @@
 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 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 @@
 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 @@
 		return;
 	}
 
-	nl = (struct net_local *)dev->priv;
+	nl = netdev_priv(dev);
 	rcv = &nl->rcv_data;
 
 	spin_lock_irq (&nl->lock);
@@ -961,7 +961,7 @@
 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 @@
                  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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 		                 "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 @@
 
 	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 -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
--- a/drivers/net/ppp_generic.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/ppp_generic.c	Sat Apr  3 19:38:55 2004
@@ -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_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 @@
 	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 @@
 	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 -Nru a/drivers/net/rrunner.c b/drivers/net/rrunner.c
--- a/drivers/net/rrunner.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/rrunner.c	Sat Apr  3 19:38:42 2004
@@ -108,7 +108,7 @@
 		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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 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 @@
 
 			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 @@
 	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 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 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 @@
 	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 @@
 
 	netif_stop_queue(dev);
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
 
 	/*
@@ -1418,7 +1426,7 @@
 
 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 @@
 {
 	struct rr_private *rrpriv;
 
-	rrpriv = (struct rr_private *)dev->priv;
+	rrpriv = netdev_priv(dev);
 
 	return(&rrpriv->stats);
 }
@@ -1511,7 +1519,7 @@
 	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 @@
 	unsigned int i;
 	int error = -EOPNOTSUPP;
 
-	rrpriv = dev->priv;
+	rrpriv = netdev_priv(dev);
 
 	switch(cmd){
 	case SIOCRRGFW:
diff -Nru a/drivers/net/sb1000.c b/drivers/net/sb1000.c
--- a/drivers/net/sb1000.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/sb1000.c	Sat Apr  3 19:38:41 2004
@@ -746,7 +746,7 @@
 	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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 	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 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 @@
 {
 	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 -Nru a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
--- a/drivers/net/sb1250-mac.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/sb1250-mac.c	Sat Apr  3 19:38:55 2004
@@ -2080,7 +2080,7 @@
 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 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 @@
 	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_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 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_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 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 @@
 {
 	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 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_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 @@
 	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 -Nru a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
--- a/drivers/net/seeq8005.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/seeq8005.c	Sat Apr  3 19:38:54 2004
@@ -357,7 +357,7 @@
    */
 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 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 @@
 	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 @@
 /* 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 @@
 /* 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 @@
    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 @@
 
 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 -Nru a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
--- a/drivers/net/sgiseeq.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/sgiseeq.c	Sat Apr  3 19:38:55 2004
@@ -151,7 +151,7 @@
 
 static int seeq_init_ring(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = dev->priv;
 	volatile struct sgiseeq_init_block *ib = &sp->srings;
 	int i;
 
@@ -423,7 +423,7 @@
 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 = dev->priv;
 	struct hpc3_ethregs *hregs = sp->hregs;
 	struct sgiseeq_regs *sregs = sp->sregs;
 
@@ -445,7 +445,7 @@
 
 static int sgiseeq_open(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv;
+	struct sgiseeq_private *sp = dev->priv;
 	struct sgiseeq_regs *sregs = sp->sregs;
 
 	int err = init_seeq(dev, sp, sregs);
@@ -459,7 +459,7 @@
 
 static int sgiseeq_close(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = dev->priv;
 	struct sgiseeq_regs *sregs = sp->sregs;
 
 	netif_stop_queue(dev);
@@ -472,7 +472,7 @@
 
 static inline int sgiseeq_reset(struct net_device *dev)
 {
-	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
+	struct sgiseeq_private *sp = dev->priv;
 	struct sgiseeq_regs *sregs = sp->sregs;
 	int err;
 
@@ -494,7 +494,7 @@
 
 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 = dev->priv;
 	struct hpc3_ethregs *hregs = sp->hregs;
 	unsigned long flags;
 	struct sgiseeq_tx_desc *td;
@@ -560,7 +560,7 @@
 
 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 = dev->priv;
 
 	return &sp->stats;
 }
@@ -710,7 +710,7 @@
 	struct net_device *next, *dev = root_sgiseeq_dev;
 
 	while (dev) {
-		sp = (struct sgiseeq_private *) dev->priv;
+		sp = dev->priv;
 		next = sp->next_module;
 		unregister_netdev(dev);
 		free_irq(dev->irq, dev);
diff -Nru a/drivers/net/sis190.c b/drivers/net/sis190.c
--- a/drivers/net/sis190.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/net/sis190.c	Sat Apr  3 19:38:57 2004
@@ -1016,14 +1016,20 @@
 			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 -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c
--- a/drivers/net/sis900.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/sis900.c	Sat Apr  3 19:38:43 2004
@@ -1650,9 +1650,6 @@
 				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 -Nru a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
--- a/drivers/net/sk98lin/skge.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/sk98lin/skge.c	Sat Apr  3 19:38:41 2004
@@ -2533,12 +2533,6 @@
 				"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 @@
 			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 -Nru a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c
--- a/drivers/net/sk98lin/skgepnmi.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/sk98lin/skgepnmi.c	Sat Apr  3 19:38:54 2004
@@ -7684,7 +7684,7 @@
 			 to the low-power state.
 			 A miniport driver must always return NDIS_STATUS_SUCCESS
 			 to a query of OID_PNP_QUERY_POWER. */
-			*pLen = sizeof(SK_DEVICE_POWER_STATE);;
+			*pLen = sizeof(SK_DEVICE_POWER_STATE);
             RetCode = SK_PNMI_ERR_OK;
 			break;
 
diff -Nru a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c
--- a/drivers/net/sk_g16.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/net/sk_g16.c	Sat Apr  3 19:38:57 2004
@@ -650,7 +650,7 @@
     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 @@
 
     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 @@
 {
     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 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 @@
 {
     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 @@
 {
     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 @@
 
     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 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 @@
 {
 
     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 -Nru a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
--- a/drivers/net/smc-mca.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/smc-mca.c	Sat Apr  3 19:38:41 2004
@@ -324,6 +324,9 @@
 
 	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 -Nru a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
--- a/drivers/net/smc-ultra.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/smc-ultra.c	Sat Apr  3 19:38:41 2004
@@ -121,6 +121,14 @@
 #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 @@
 
 	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 @@
 	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 -Nru a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
--- a/drivers/net/smc-ultra32.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/smc-ultra32.c	Sat Apr  3 19:38:55 2004
@@ -268,6 +268,9 @@
 	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 -Nru a/drivers/net/smc9194.c b/drivers/net/smc9194.c
--- a/drivers/net/smc9194.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/smc9194.c	Sat Apr  3 19:38:54 2004
@@ -465,7 +465,7 @@
 */
 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 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 @@
 {
 	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 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 @@
 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 @@
  . 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 -Nru a/drivers/net/starfire.c b/drivers/net/starfire.c
--- a/drivers/net/starfire.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/starfire.c	Sat Apr  3 19:38:42 2004
@@ -1637,10 +1637,13 @@
 		    && (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 -Nru a/drivers/net/stnic.c b/drivers/net/stnic.c
--- a/drivers/net/stnic.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/stnic.c	Sat Apr  3 19:38:45 2004
@@ -20,7 +20,7 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
-#include <asm/hitachi_se.h>
+#include <asm/se/se.h>
 #include <asm/machvec.h>
 #ifdef CONFIG_SH_STANDARD_BIOS 
 #include <asm/sh_bios.h>
@@ -124,6 +124,9 @@
   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 -Nru a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
--- a/drivers/net/sun3lance.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/sun3lance.c	Sat Apr  3 19:38:55 2004
@@ -332,7 +332,7 @@
 		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 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 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 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 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 @@
 /* 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_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 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 @@
 /* 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 -Nru a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
--- a/drivers/net/sunbmac.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/sunbmac.c	Sat Apr  3 19:38:43 2004
@@ -849,9 +849,13 @@
 			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 -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c
--- a/drivers/net/sundance.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/sundance.c	Sat Apr  3 19:38:44 2004
@@ -1331,9 +1331,6 @@
 		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 @@
 				&& (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 -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c
--- a/drivers/net/sungem.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/sungem.c	Sat Apr  3 19:38:56 2004
@@ -763,8 +763,9 @@
 			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 -Nru a/drivers/net/sunhme.c b/drivers/net/sunhme.c
--- a/drivers/net/sunhme.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/sunhme.c	Sat Apr  3 19:38:42 2004
@@ -273,8 +273,10 @@
 	((__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 @@
 	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 @@
 	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 @@
 			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 @@
 	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 @@
 	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 -Nru a/drivers/net/sunhme.h b/drivers/net/sunhme.h
--- a/drivers/net/sunhme.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/sunhme.h	Sat Apr  3 19:38:43 2004
@@ -406,7 +406,8 @@
 	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 -Nru a/drivers/net/sunlance.c b/drivers/net/sunlance.c
--- a/drivers/net/sunlance.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/sunlance.c	Sat Apr  3 19:38:42 2004
@@ -313,7 +313,7 @@
 /* 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_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 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_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_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_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 @@
 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 @@
 
 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_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_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_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 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 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 @@
 /* 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_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 @@
 /* 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 @@
 	if (!dev)
 		return -ENOMEM;
 
-	lp = dev->priv;
+	lp = netdev_priv(dev);
 
 	if (sparc_lance_debug && version_printed++ == 0)
 		printk (KERN_INFO "%s", version);
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/tg3.c	Sat Apr  3 19:38:44 2004
@@ -2280,8 +2280,9 @@
 			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 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 @@
 	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 -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c
--- a/drivers/net/tlan.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/tlan.c	Sat Apr  3 19:38:41 2004
@@ -814,6 +814,14 @@
 
 } /* 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 @@
 	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 -Nru a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
--- a/drivers/net/tokenring/3c359.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/tokenring/3c359.c	Sat Apr  3 19:38:56 2004
@@ -937,15 +937,17 @@
 			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 -Nru a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
--- a/drivers/net/tokenring/abyss.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/tokenring/abyss.c	Sat Apr  3 19:38:42 2004
@@ -154,7 +154,7 @@
 		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 @@
 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 @@
 	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 -Nru a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
--- a/drivers/net/tokenring/madgemc.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/tokenring/madgemc.c	Sat Apr  3 19:38:55 2004
@@ -365,7 +365,7 @@
 				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 @@
 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 @@
 	}
 	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 -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
--- a/drivers/net/tokenring/olympic.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/net/tokenring/olympic.c	Sat Apr  3 19:38:54 2004
@@ -842,10 +842,13 @@
 							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 @@
 							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 -Nru a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
--- a/drivers/net/tokenring/proteon.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/tokenring/proteon.c	Sat Apr  3 19:38:56 2004
@@ -158,7 +158,7 @@
 		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 @@
 
 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 -Nru a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
--- a/drivers/net/tokenring/skisa.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/tokenring/skisa.c	Sat Apr  3 19:38:41 2004
@@ -175,7 +175,7 @@
 		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 @@
 
 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 -Nru a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
--- a/drivers/net/tokenring/smctr.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/tokenring/smctr.c	Sat Apr  3 19:38:43 2004
@@ -327,7 +327,7 @@
  */
 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_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 @@
         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_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_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_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_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_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_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_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_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_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 __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 @@
 
 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 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 __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 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 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_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_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_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_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_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_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_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_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_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 @@
         }
 
         ioaddr = dev->base_addr;
-        tp = (struct net_local *)dev->priv;
+        tp = netdev_priv(dev);
         
 
         if(tp->status == NOT_INITIALIZED)
@@ -2471,7 +2471,7 @@
 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 @@
 /* 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 @@
 	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 @@
 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 @@
 		}
         }
 
-        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 @@
 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 @@
 /* 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_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_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_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_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_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 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_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_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_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_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_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_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 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 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_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_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_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_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 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 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_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 __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 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 @@
 /* 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_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_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_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_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 @@
 	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 @@
 
 			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 -Nru a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
--- a/drivers/net/tokenring/tms380tr.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/tokenring/tms380tr.c	Sat Apr  3 19:38:44 2004
@@ -243,7 +243,7 @@
  */
 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 @@
 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 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 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 @@
 	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_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_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 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 @@
 	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_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 @@
 		return IRQ_NONE;
 	}
 
-	tp = (struct net_local *)dev->priv;
+	tp = netdev_priv(dev);
 
 	irq_type = SIFREADW(SIFSTS);
 
@@ -843,7 +843,7 @@
  */
 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 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 @@
  */
 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 @@
  */
 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 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 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_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 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_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 @@
 {
 	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 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_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_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 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 @@
 {
 	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 @@
 	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 -Nru a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
--- a/drivers/net/tulip/21142.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/tulip/21142.c	Sat Apr  3 19:38:42 2004
@@ -8,7 +8,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
@@ -29,7 +29,7 @@
 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_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_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 -Nru a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
--- a/drivers/net/tulip/de2104x.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/tulip/de2104x.c	Sat Apr  3 19:38:55 2004
@@ -28,8 +28,8 @@
  */
 
 #define DRV_NAME		"de2104x"
-#define DRV_VERSION		"0.6"
-#define DRV_RELDATE		"Sep 1, 2003"
+#define DRV_VERSION		"0.7"
+#define DRV_RELDATE		"Mar 17, 2004"
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -303,7 +303,6 @@
 	struct net_device_stats net_stats;
 
 	struct pci_dev		*pdev;
-	u32			macmode;
 
 	u16			setup_frame[DE_SETUP_FRAME_WORDS];
 
@@ -457,10 +456,12 @@
 					       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;
 		}
@@ -730,7 +731,7 @@
 	struct de_desc *txd;
 	struct de_desc *dummy_txd = NULL;
 
-	macmode = de->macmode & ~(AcceptAllMulticast | AcceptAllPhys);
+	macmode = dr32(MacMode) & ~(AcceptAllMulticast | AcceptAllPhys);
 
 	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
 		macmode |= AcceptAllMulticast | AcceptAllPhys;
@@ -803,10 +804,8 @@
 	dw32(TxPoll, NormalTxPoll);
 
 out:
-	if (macmode != de->macmode) {
-		dw32 (MacMode, macmode);
-		de->macmode = macmode;
-	}
+	if (macmode != dr32(MacMode))
+		dw32(MacMode, macmode);
 }
 
 static void de_set_rx_mode (struct net_device *dev)
@@ -921,6 +920,7 @@
 static void de_set_media (struct de_private *de)
 {
 	unsigned media = de->media_type;
+	u32 macmode = dr32(MacMode);
 
 	if (de_is_running(de))
 		BUG();
@@ -938,9 +938,9 @@
 	mdelay(10);
 
 	if (media == DE_MEDIA_TP_FD)
-		de->macmode |= FullDuplex;
+		macmode |= FullDuplex;
 	else
-		de->macmode &= ~FullDuplex;
+		macmode &= ~FullDuplex;
 	
 	if (netif_msg_link(de)) {
 		printk(KERN_INFO "%s: set link %s\n"
@@ -949,9 +949,11 @@
 		       de->dev->name, media_name[media],
 		       de->dev->name, dr32(MacMode), dr32(SIAStatus),
 		       dr32(CSR13), dr32(CSR14), dr32(CSR15),
-		       de->dev->name, de->macmode, de->media[media].csr13,
+		       de->dev->name, macmode, de->media[media].csr13,
 		       de->media[media].csr14, de->media[media].csr15);
 	}
+	if (macmode != dr32(MacMode))
+		dw32(MacMode, macmode);
 }
 
 static void de_next_media (struct de_private *de, u32 *media,
@@ -1171,18 +1173,18 @@
 	u32 status, tmp;
 
 	/*
-	 * Reset MAC.  Copied from de4x5.c.
+	 * Reset MAC.  de4x5.c and tulip.c examined for "advice"
+	 * in this area.
 	 */
 
-	tmp = dr32 (BusMode);
-	if (tmp == 0xffffffff)
-		return -ENODEV;
-	mdelay (1);
+	if (dr32(BusMode) == 0xffffffff)
+		return -EBUSY;
 
-	dw32 (BusMode, tmp | CmdReset);
+	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+	dw32 (BusMode, CmdReset);
 	mdelay (1);
 
-	dw32 (BusMode, tmp);
+	dw32 (BusMode, de_bus_mode);
 	mdelay (1);
 
 	for (tmp = 0; tmp < 5; tmp++) {
@@ -1233,11 +1235,12 @@
 static int de_init_hw (struct de_private *de)
 {
 	struct net_device *dev = de->dev;
+	u32 macmode;
 	int rc;
 
 	de_adapter_wake(de);
 	
-	de->macmode = dr32(MacMode) & ~MacModeClear;
+	macmode = dr32(MacMode) & ~MacModeClear;
 
 	rc = de_reset_mac(de);
 	if (rc)
@@ -1248,7 +1251,7 @@
 	dw32(RxRingAddr, de->ring_dma);
 	dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE));
 
-	dw32(MacMode, RxTx | de->macmode);
+	dw32(MacMode, RxTx | macmode);
 
 	dr32(RxMissed); /* self-clearing */
 
@@ -1499,7 +1502,7 @@
 		break;
 	}
 	
-	if (de->macmode & FullDuplex)
+	if (dr32(MacMode) & FullDuplex)
 		ecmd->duplex = DUPLEX_FULL;
 	else
 		ecmd->duplex = DUPLEX_HALF;
diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
--- a/drivers/net/tulip/de4x5.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/tulip/de4x5.c	Sat Apr  3 19:38:40 2004
@@ -1086,7 +1086,7 @@
 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 @@
 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 @@
 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 @@
 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 @@
 	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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 		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 @@
     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 @@
 	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 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 @@
 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 @@
 	      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 @@
 		      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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
     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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 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 -Nru a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
--- a/drivers/net/tulip/dmfe.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/tulip/dmfe.c	Sat Apr  3 19:38:55 2004
@@ -392,7 +392,7 @@
 	}
 
 	/* 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 @@
 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 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 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 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_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 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 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 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 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 @@
 	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_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 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 -Nru a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
--- a/drivers/net/tulip/eeprom.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/tulip/eeprom.c	Sat Apr  3 19:38:55 2004
@@ -8,7 +8,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
@@ -136,7 +136,7 @@
 	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 -Nru a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
--- a/drivers/net/tulip/interrupt.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/tulip/interrupt.c	Sat Apr  3 19:38:42 2004
@@ -8,7 +8,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
@@ -63,7 +63,7 @@
 
 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 @@
 
 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 @@
                                    && (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 @@
                                               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 @@
 
 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 @@
 				&& (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 @@
 				       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 @@
 {
 #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 @@
 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 -Nru a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
--- a/drivers/net/tulip/media.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/tulip/media.c	Sat Apr  3 19:38:42 2004
@@ -8,7 +8,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
@@ -48,7 +48,7 @@
 
 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 @@
 
 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_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 @@
   */
 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 @@
 
 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 -Nru a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
--- a/drivers/net/tulip/pnic.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/tulip/pnic.c	Sat Apr  3 19:38:45 2004
@@ -8,7 +8,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
@@ -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_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_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 -Nru a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
--- a/drivers/net/tulip/pnic2.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/tulip/pnic2.c	Sat Apr  3 19:38:41 2004
@@ -9,7 +9,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
@@ -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_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_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 -Nru a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
--- a/drivers/net/tulip/timer.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/tulip/timer.c	Sat Apr  3 19:38:40 2004
@@ -8,7 +8,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
@@ -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 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 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 -Nru a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
--- a/drivers/net/tulip/tulip.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/tulip/tulip.h	Sat Apr  3 19:38:55 2004
@@ -7,7 +7,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
--- a/drivers/net/tulip/tulip_core.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/tulip/tulip_core.c	Sat Apr  3 19:38:44 2004
@@ -8,7 +8,7 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	Please refer to Documentation/DocBook/tulip.{pdf,ps,html}
+	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}
 	for more information on this driver, or visit the project
 	Web page at http://sourceforge.net/projects/tulip/
 
@@ -253,8 +253,9 @@
 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);
-
-
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void poll_tulip(struct net_device *dev);
+#endif
 
 static void tulip_set_power_state (struct tulip_private *tp,
 				   int sleep, int snooze)
@@ -276,7 +277,7 @@
 
 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 +500,7 @@
 
 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 +588,7 @@
 /* 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 +639,7 @@
 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 +725,7 @@
 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 +765,7 @@
 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 +812,7 @@
 
 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 +831,7 @@
 
 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 +856,7 @@
 /* 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 +965,7 @@
 
 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 +996,7 @@
 
 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 +1024,7 @@
 
 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 +1151,7 @@
 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 +1374,7 @@
 	 * 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 +
@@ -1618,6 +1619,9 @@
 	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 +1760,7 @@
 	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 +1778,22 @@
 	/* 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 -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
--- a/drivers/net/tulip/winbond-840.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/tulip/winbond-840.c	Sat Apr  3 19:38:41 2004
@@ -1289,9 +1289,9 @@
 				&& (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 @@
 				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 -Nru a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
--- a/drivers/net/tulip/xircom_cb.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/net/tulip/xircom_cb.c	Sat Apr  3 19:38:55 2004
@@ -178,7 +178,7 @@
 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 @@
 		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 @@
 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 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 @@
 	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_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 @@
 	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 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 -Nru a/drivers/net/tun.c b/drivers/net/tun.c
--- a/drivers/net/tun.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/tun.c	Sat Apr  3 19:38:43 2004
@@ -70,7 +70,7 @@
 /* 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 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 @@
 /* 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)
@@ -169,7 +169,7 @@
 	return mask;
 }
 
-/* Get packet from user space buffer(already verified) */
+/* Get packet from user space buffer */
 static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count)
 {
 	struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) };
@@ -180,7 +180,8 @@
 		if ((len -= sizeof(pi)) > len)
 			return -EINVAL;
 
-		memcpy_fromiovec((void *)&pi, iv, sizeof(pi));
+		if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi)))
+			return -EFAULT;
 	}
  
 	if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
@@ -189,7 +190,8 @@
 	}
 
 	skb_reserve(skb, 2);
-	memcpy_fromiovec(skb_put(skb, len), iv, len);
+	if (memcpy_fromiovec(skb_put(skb, len), iv, len))
+		return -EFAULT;
 
 	skb->dev = tun->dev;
 	switch (tun->flags & TUN_TYPE_MASK) {
@@ -213,26 +215,29 @@
 	return count;
 } 
 
+static inline size_t iov_total(const struct iovec *iv, unsigned long count)
+{
+	unsigned long i;
+	size_t len;
+
+	for (i = 0, len = 0; i < count; i++) 
+		len += iv[i].iov_len;
+
+	return len;
+}
+
 /* Writev */
 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;
-	unsigned long i;
-	size_t len;
+	struct tun_struct *tun = file->private_data;
 
 	if (!tun)
 		return -EBADFD;
 
 	DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count);
 
-	for (i = 0, len = 0; i < count; i++) {
-		if (verify_area(VERIFY_READ, iv[i].iov_base, iv[i].iov_len))
-			return -EFAULT;
-		len += iv[i].iov_len;
-	}
-
-	return tun_get_user(tun, (struct iovec *) iv, len);
+	return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count));
 }
 
 /* Write */
@@ -243,7 +248,7 @@
 	return tun_chr_writev(file, &iv, 1, pos);
 }
 
-/* Put packet to the user space buffer (already verified) */
+/* Put packet to the user space buffer */
 static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
 				       struct sk_buff *skb,
 				       struct iovec *iv, int len)
@@ -260,7 +265,8 @@
 			pi.flags |= TUN_PKT_STRIP;
 		}
  
-		memcpy_toiovec(iv, (void *) &pi, sizeof(pi));
+		if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi)))
+			return -EFAULT;
 		total += sizeof(pi);
 	}       
 
@@ -279,22 +285,17 @@
 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;
-	unsigned long i;
 
 	if (!tun)
 		return -EBADFD;
 
 	DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
 
-	for (i = 0, len = 0; i < count; i++) {
-		if (verify_area(VERIFY_WRITE, iv[i].iov_base, iv[i].iov_len))
-			return -EFAULT;
-		len += iv[i].iov_len;
-	}
+	len = iov_total(iv, count);
 	if (len < 0)
 		return -EINVAL;
 
@@ -341,7 +342,7 @@
 
 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 +414,7 @@
 		if (!dev)
 			return -ENOMEM;
 
-		tun = dev->priv;
+		tun = netdev_priv(dev);
 		tun->dev = dev;
 		tun->flags = flags;
 
@@ -455,7 +456,7 @@
 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 +528,7 @@
 
 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 +559,7 @@
 
 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;
@@ -602,21 +603,22 @@
 
 static struct miscdevice tun_miscdev = {
 	.minor = TUN_MINOR,
-	.name = "net/tun",
-	.fops = &tun_fops
+	.name = "tun",
+	.fops = &tun_fops,
+	.devfs_name = "net/tun",
 };
 
 int __init tun_init(void)
 {
+	int ret = 0;
+
 	printk(KERN_INFO "Universal TUN/TAP device driver %s " 
 	       "(C)1999-2002 Maxim Krasnyansky\n", TUN_VER);
 
-	if (misc_register(&tun_miscdev)) {
+	ret = misc_register(&tun_miscdev);
+	if (ret)
 		printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR);
-		return -EIO;
-	}
-
-	return 0;
+	return ret;
 }
 
 void tun_cleanup(void)
diff -Nru a/drivers/net/typhoon.c b/drivers/net/typhoon.c
--- a/drivers/net/typhoon.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/typhoon.c	Sat Apr  3 19:38:45 2004
@@ -1318,7 +1318,7 @@
 	tp->rxHiRing.ringBase = (u8 *) tp->shared->rxHi;
 	tp->rxBuffRing.ringBase = (u8 *) tp->shared->rxBuff;
 	tp->cmdRing.ringBase = (u8 *) tp->shared->cmd;
-	tp->respRing.ringBase = (u8 *) tp->shared->resp;;
+	tp->respRing.ringBase = (u8 *) tp->shared->resp;
 
 	tp->txLoRing.writeRegister = TYPHOON_REG_TX_LO_READY;
 	tp->txHiRing.writeRegister = TYPHOON_REG_TX_HI_READY;
@@ -1701,9 +1701,13 @@
 		   (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 -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
--- a/drivers/net/via-rhine.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/via-rhine.c	Sat Apr  3 19:38:56 2004
@@ -615,6 +615,15 @@
 			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 @@
 	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 @@
 				(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 @@
 				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 -Nru a/drivers/net/wan/comx-hw-locomx.c b/drivers/net/wan/comx-hw-locomx.c
--- a/drivers/net/wan/comx-hw-locomx.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/wan/comx-hw-locomx.c	Sat Apr  3 19:38:45 2004
@@ -77,7 +77,7 @@
 
 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 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 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 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 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 @@
 
 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_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 @@
 
 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 -Nru a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c
--- a/drivers/net/wan/comx-hw-munich.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/wan/comx-hw-munich.c	Sat Apr  3 19:38:42 2004
@@ -373,7 +373,7 @@
 
 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 @@
 {
     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 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 @@
 #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 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 @@
 		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 @@
 
 	    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 @@
 		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 @@
 	    {
 		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 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_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_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 @@
 {
     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 @@
 {
     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 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_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 -Nru a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c
--- a/drivers/net/wan/comx.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/net/wan/comx.c	Sat Apr  3 19:38:43 2004
@@ -379,7 +379,7 @@
 
 static struct net_device_stats *comx_stats(struct net_device *dev)
 {
-	struct comx_channel *ch = (struct comx_channel *)dev->priv;
+	struct comx_channel *ch = dev->priv;
 
 	return ch->current_stats;
 }
@@ -535,7 +535,7 @@
 {
 	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 = dev->priv;
 	int len = 0;
 
 	if (strcmp(file->name, FILENAME_STATUS) == 0) {
@@ -599,7 +599,7 @@
 {
 	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 = dev->priv;
 	char *page;
 	struct comx_hardware *hw = comx_channels;
 	struct comx_protocol *line = comx_lines;
@@ -821,7 +821,7 @@
 	if (register_netdevice(dev)) {
 		goto cleanup_filename_debug;
 	}
-	ch=dev->priv;
+	ch = dev->priv;
 	if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device), 
 				 GFP_KERNEL)) == NULL) {
 		goto cleanup_register;
diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
--- a/drivers/net/wan/cosa.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/net/wan/cosa.c	Sat Apr  3 19:38:40 2004
@@ -807,7 +807,7 @@
 {
 	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 @@
 	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_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 @@
 	int cmd)
 {
 	int rv;
-	struct channel_data *chan = (struct channel_data *)dev->priv;
+	struct channel_data *chan = dev->priv;
 	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_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 -Nru a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
--- a/drivers/net/wan/dscc4.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/wan/dscc4.c	Sat Apr  3 19:38:42 2004
@@ -652,7 +652,6 @@
 		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 -Nru a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
--- a/drivers/net/wan/lapbether.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/wan/lapbether.c	Sat Apr  3 19:38:42 2004
@@ -198,7 +198,7 @@
 
 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 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 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 @@
 	if (!ndev)
 		goto out;
 
-	lapbeth = ndev->priv;
+	lapbeth = netdev_priv(ndev);
 	lapbeth->axdev = ndev;
 
 	dev_hold(dev);
@@ -397,7 +397,7 @@
 				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 -Nru a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
--- a/drivers/net/wan/pc300_drv.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/net/wan/pc300_drv.c	Sat Apr  3 19:38:56 2004
@@ -3661,7 +3661,7 @@
 			release_mem_region(card->hw.falcphys, card->hw.falcsize);
 		}
 		for (i = 0; i < card->hw.nchan; i++)
-			if (card->chan[i].d.dev);
+			if (card->chan[i].d.dev)
 				free_netdev(card->chan[i].d.dev);
 		if (card->hw.irq)
 			free_irq(card->hw.irq, card);
diff -Nru a/drivers/net/wd.c b/drivers/net/wd.c
--- a/drivers/net/wd.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/wd.c	Sat Apr  3 19:38:41 2004
@@ -333,6 +333,9 @@
 	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 -Nru a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
--- a/drivers/net/wireless/Kconfig	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/wireless/Kconfig	Sat Apr  3 19:38:42 2004
@@ -307,6 +307,54 @@
 	 It has basic support for Linux wireless extensions and initial
 	 micro support for ethtool.
 
+comment "Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support"
+	depends on NET_RADIO && PCI
+config PRISM54
+	tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' 
+	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
+	  SMC2835W-V2 - 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 -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
--- a/drivers/net/wireless/Makefile	Sat Apr  3 19:38:57 2004
+++ b/drivers/net/wireless/Makefile	Sat Apr  3 19:38:57 2004
@@ -26,6 +26,8 @@
 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 -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/wireless/airo.c	Sat Apr  3 19:38:41 2004
@@ -1505,7 +1505,7 @@
 	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 -Nru a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
--- a/drivers/net/wireless/arlan-main.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/net/wireless/arlan-main.c	Sat Apr  3 19:38:45 2004
@@ -1281,7 +1281,7 @@
 			priv->retransmissions = 0;
 			if (priv->Conf->tx_delay_ms)
 			{
-				priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1;;
+				priv->tx_done_delayed = jiffies + (priv->Conf->tx_delay_ms * HZ) / 1000 + 1;
 			}
 			else
 			{
diff -Nru a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
--- a/drivers/net/wireless/atmel.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/wireless/atmel.c	Sat Apr  3 19:38:42 2004
@@ -537,7 +537,7 @@
 	int channel;
 	int reg_domain;
 	int tx_rate;
-	int auto_tx_rate;;
+	int auto_tx_rate;
 	int rts_threshold;
 	int frag_threshold;
 	int long_retry, short_retry;
@@ -796,7 +796,7 @@
 
 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 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 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_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_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_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 @@
 		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 @@
 
 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 @@
 			   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 @@
 			   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 @@
 			 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 @@
 			    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 @@
 			    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 @@
 			  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 @@
 			  __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 @@
 			  __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 @@
 			 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 @@
 			   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 @@
 			   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 @@
 			   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 @@
 			   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 @@
 			 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 @@
 			 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 @@
 			  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 @@
 			  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 @@
 			  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 @@
 			  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 @@
 			  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 @@
 			  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 @@
 			   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 @@
 			 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 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_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 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 @@
 	   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 -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h
--- a/drivers/net/wireless/hermes.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/net/wireless/hermes.h	Sat Apr  3 19:38:41 2004
@@ -364,7 +364,7 @@
 /* Note that for the next two, the count is in 16-bit words, not bytes */
 static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count)
 {
-	off = off << hw->reg_spacing;;
+	off = off << hw->reg_spacing;
 
 	if (hw->io_space) {
 		insw(hw->iobase + off, buf, count);
diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
--- a/drivers/net/wireless/orinoco.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/net/wireless/orinoco.c	Sat Apr  3 19:38:57 2004
@@ -599,7 +599,7 @@
 
 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_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_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 @@
 
 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 @@
 
 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 @@
 
 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 @@
 /* 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 @@
  * 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 @@
 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 @@
 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 __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_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_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_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_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 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 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 @@
 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 @@
 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 @@
 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 @@
 		    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 @@
 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 @@
 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 @@
 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 @@
 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 @@
 
 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_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_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_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_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_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_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_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_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_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_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_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 @@
 
 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_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_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_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_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 @@
 #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_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_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_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_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 @@
  * 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_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(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 @@
 
 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 @@
 	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 -Nru a/drivers/net/wireless/prism54/Makefile b/drivers/net/wireless/prism54/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/Makefile	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/isl_38xx.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/isl_38xx.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/isl_ioctl.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,2211 @@
+/*  $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 <linux/moduleparam.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_param(init_mode, int, 0);
+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_param(init_channel, int, 0);
+MODULE_PARM_DESC(init_channel,
+		 "Check `iwpriv ethx channel` for available channels");
+
+module_param(init_wep, int, 0);
+module_param(init_filter, int, 0);
+
+module_param(init_authen, int, 0);
+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_param(init_dot1x, int, 0);
+MODULE_PARM_DESC(init_dot1x,
+		 "\n0: None/not set	(Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED");
+
+module_param(init_mlme, int, 0);
+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 = netdev_priv(ndev);
+
+	/* 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 = netdev_priv(ndev);
+
+	/* 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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+
+	/* 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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+
+	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 = netdev_priv(ndev);
+
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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(netdev_priv(ndev), 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 *) netdev_priv(ndev),
+				     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 *) netdev_priv(ndev),
+			    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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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(netdev_priv(ndev), 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(netdev_priv(ndev), 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 = netdev_priv(ndev);
+
+	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(netdev_priv(ndev), "Link established");
+	} else
+		send_simple_event(netdev_priv(ndev), "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;
+	struct net_device *ndev = frame->ndev;
+	enum oid_num_t n = mgt_oidtonum(frame->header->oid);
+
+	prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
+	islpci_mgt_release(frame);
+}
+
+int
+prism54_set_mac_address(struct net_device *ndev, void *addr)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+
+	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 = netdev_priv(ndev);
+	*uwrq = priv->wpa;
+	return 0;
+}
+
+int
+prism54_set_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
+		__u32 *uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	u32 max_burst;
+
+	max_burst = (*uwrq) ? *uwrq : CARD_DEFAULT_MAXFRAMEBURST;
+	mgt_set_request(priv, DOT11_OID_MAXFRAMEBURST, 0, &max_burst);
+
+	return -EINPROGRESS; /* Call commit handler */
+}
+
+int
+prism54_get_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
+		__u32 *uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue;
+	
+	rvalue = mgt_get_request(priv, DOT11_OID_MAXFRAMEBURST, 0, NULL, &r);
+	*uwrq = r.u;
+	
+	return rvalue;
+}
+
+int
+prism54_set_profile(struct net_device *ndev, struct iw_request_info *info,
+		__u32 *uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	u32 profile;
+
+	profile = (*uwrq) ? *uwrq : CARD_DEFAULT_PROFILE;
+	mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
+	
+	return -EINPROGRESS; /* Call commit handler */
+}
+
+int
+prism54_get_profile(struct net_device *ndev, struct iw_request_info *info,
+		__u32 *uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	union oid_res_t r;
+	int rvalue;
+
+	rvalue = mgt_get_request(priv, DOT11_OID_PROFILES, 0, NULL, &r);
+	*uwrq = r.u;
+
+	return rvalue;
+}
+
+int
+prism54_oid(struct net_device *ndev, struct iw_request_info *info,
+		__u32 *uwrq, char *extra)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 -Nru a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/isl_ioctl.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/isl_oid.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,483 @@
+/*
+ *  $Id: isl_oid.h,v 1.3 2004/03/09 09:05:27 mcgrof Exp $
+ *  
+ *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
+ *  Copyright (C) 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
+ *
+ */
+
+#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
+};
+
+/* Prism "Nitro" / Frameburst / "Packet Frame Grouping"
+ * Value is in microseconds. Represents the # microseconds
+ * the firmware will take to group frames before sending out then out 
+ * together with a CSMA contention. Without this all frames are
+ * sent with a CSMA contention. 
+ * Bibliography: 
+ * http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html
+ */
+enum dot11_maxframeburst_t { 
+	/* Values for DOT11_OID_MAXFRAMEBURST */
+	DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */
+	DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */
+	DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */
+	DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max,
+		* Note: firmware allows for greater values. This is a
+		* recommended max. I'll update this as I find
+		* out what the real MAX is. Also note that you don't necessarily
+		* get better results with a greater value here.
+		*/
+};
+
+/* Support for 802.11 long and short frame preambles.
+ * Long	 preamble uses 128-bit sync field, 8-bit  CRC
+ * Short preamble uses 56-bit  sync field, 16-bit CRC
+ * 
+ * 802.11a -- not sure, both optionally ?
+ * 802.11b supports long and optionally short 
+ * 802.11g supports both */
+enum dot11_preamblesettings_t {
+	DOT11_PREAMBLESETTING_LONG = 0,
+		/* Allows *only* long 802.11 preambles */
+	DOT11_PREAMBLESETTING_SHORT = 1,
+		/* Allows *only* short 802.11 preambles */
+	DOT11_PREAMBLESETTING_DYNAMIC = 2
+		/* AutomatiGically set */
+};
+
+/* Support for 802.11 slot timing (time between packets).
+ *
+ * Long uses 802.11a slot timing  (9 usec ?)
+ * Short uses 802.11b slot timing (20 use ?) */
+enum dot11_slotsettings_t {
+	DOT11_SLOTSETTINGS_LONG = 0, 
+		/* Allows *only* long 802.11b slot timing */
+	DOT11_SLOTSETTINGS_SHORT = 1,
+		/* Allows *only* long 802.11a slot timing */
+	DOT11_SLOTSETTINGS_DYNAMIC = 2
+		/* AutomatiGically set */
+};
+
+/* All you need to know, ERP is "Extended Rate PHY".
+ * An Extended Rate PHY (ERP) STA or AP shall support three different 
+ * preamble and header formats:
+ * Long  preamble (refer to above)
+ * Short preamble (refer to above)
+ * OFDM  preamble ( ? )
+ *
+ * I'm assuming here Protection tells the AP
+ * to be careful, a STA which cannot handle the long pre-amble
+ * has joined.
+ */
+enum do11_nonerpstatus_t {
+	DOT11_ERPSTAT_NONEPRESENT = 0,
+	DOT11_ERPSTAT_USEPROTECTION = 1
+};
+
+/* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-*
+ * The key here is DOT11 NON ERP NEVER protects against
+ * NON ERP STA's. You *don't* want this unless
+ * you know what you are doing. It means you will only 
+ * get Extended Rate capabilities */
+enum dot11_nonerpprotection_t {
+	DOT11_NONERP_NEVER = 0,
+	DOT11_NONERP_ALWAYS = 1,
+	DOT11_NONERP_DYNAMIC = 2
+};
+
+/* Preset OID configuration for 802.11 modes 
+ * Note: DOT11_OID_CW[MIN|MAX] hold the values of the 
+ * DCS MIN|MAX backoff used */
+enum dot11_profile_t { /* And set/allowed values */
+	/* Allowed values for DOT11_OID_PROFILES */
+	DOT11_PROFILE_B_ONLY = 0,
+		/* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps 
+		 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
+		 * DOT11_OID_CWMIN: 31
+		 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
+		 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG
+		 */
+	DOT11_PROFILE_MIXED_G_WIFI = 1,
+		/* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs
+		 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
+		 * DOT11_OID_CWMIN: 15
+		 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
+		 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC
+		 */
+	DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */
+		/* Same as Profile MIXED_G_WIFI */
+	DOT11_PROFILE_G_ONLY = 3,
+		/* Same as Profile MIXED_G_WIFI */
+	DOT11_PROFILE_TEST = 4,
+		/* Same as Profile MIXED_G_WIFI except:
+		 * DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT
+		 * DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER
+		 * DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT
+		 */
+	DOT11_PROFILE_B_WIFI = 5,
+		/* Same as Profile B_ONLY */
+	DOT11_PROFILE_A_ONLY = 6,
+		/* Same as Profile MIXED_G_WIFI except:
+		 * DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs
+		 */
+	DOT11_PROFILE_MIXED_SHORT = 7
+		/* Same as MIXED_G_WIFI */
+};
+
+
+/* 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, /* MIN DCS backoff */
+	DOT11_OID_CWMAX, /* MAX DCS backoff */
+	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 -Nru a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/islpci_dev.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,827 @@
+/*  $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 = netdev_priv(ndev);
+
+	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 = netdev_priv(ndev);
+
+	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 = netdev_priv(ndev);
+
+#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");
+			skb = NULL;
+			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 = netdev_priv(ndev);
+	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 -Nru a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/islpci_dev.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/islpci_eth.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,434 @@
+/*  $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);
+			skb = NULL;
+		}
+		/* 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 = netdev_priv(ndev);
+	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);
+	skb = NULL;
+
+	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);
+		skb = NULL;
+	}
+	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);
+			skb = NULL;
+			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 = netdev_priv(ndev);
+	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 -Nru a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/islpci_eth.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,436 @@
+/*  $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.1"
+
+MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
+MODULE_DESCRIPTION("The Prism54 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_ISL3890,
+	 PCIVENDOR_SMC, 0xa835UL,
+	 0, 0,
+	 (unsigned long) "SMC 2835Wv2"},
+	{
+	 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 = netdev_priv(ndev);
+	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;
+	case 0xa835UL:
+		modelp = "SMC2835W V2";
+		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 = netdev_priv(ndev);
+	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 ? netdev_priv(ndev) : 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 ? netdev_priv(ndev) : 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 ? netdev_priv(ndev) : 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 -Nru a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/islpci_mgt.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,511 @@
+/*  $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 <linux/moduleparam.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_param(pc_debug, int, 0);
+
+/******************************************************************************
+    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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 = netdev_priv(ndev);
+	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 -Nru a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/islpci_mgt.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,168 @@
+/*  $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
+#define CARD_DEFAULT_PROFILE			DOT11_PROFILE_MIXED_G_WIFI
+#define CARD_DEFAULT_MAXFRAMEBURST		DOT11_MAXFRAMEBURST_MIXED_SAFE
+
+/* 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 -Nru a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/oid_mgt.c	Sat Apr  3 19:38:57 2004
@@ -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), /* in microseconds */
+
+	[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 -Nru a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/wireless/prism54/oid_mgt.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
--- a/drivers/net/yellowfin.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/net/yellowfin.c	Sat Apr  3 19:38:42 2004
@@ -1124,7 +1124,7 @@
 
 		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 @@
 				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 -Nru a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
--- a/drivers/net/zorro8390.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/net/zorro8390.c	Sat Apr  3 19:38:44 2004
@@ -227,6 +227,10 @@
     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 -Nru a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
--- a/drivers/parisc/ccio-dma.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/parisc/ccio-dma.c	Sat Apr  3 19:38:41 2004
@@ -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 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 @@
 	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 @@
 ** 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 @@
 #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 @@
  * 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 @@
 	
 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 @@
 	}
 	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 @@
 
 #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 @@
 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 @@
  * 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 @@
 		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 @@
 	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 @@
 	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 @@
 		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 @@
 
 	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 @@
 */
 #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 @@
 	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 @@
 		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 @@
 	** 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 @@
 	** 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 @@
 	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 @@
 	.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 @@
 			      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 @@
 			      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 @@
 			      (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 @@
 	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 @@
 	*/
 
 	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 @@
 	}
 	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 @@
 	
 
 	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 -Nru a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c
--- a/drivers/parisc/ccio-rm-dma.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/parisc/ccio-rm-dma.c	Sat Apr  3 19:38:42 2004
@@ -151,8 +151,10 @@
 	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 -Nru a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
--- a/drivers/parisc/eisa.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/parisc/eisa.c	Sat Apr  3 19:38:40 2004
@@ -116,6 +116,16 @@
 		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 -Nru a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
--- a/drivers/parisc/gsc.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/parisc/gsc.c	Sat Apr  3 19:38:56 2004
@@ -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 -Nru a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/parisc/iommu-helpers.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
--- a/drivers/parisc/lba_pci.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/parisc/lba_pci.c	Sat Apr  3 19:38:54 2004
@@ -533,10 +533,10 @@
 	*/
 	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 @@
 	/* 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 -Nru a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
--- a/drivers/parisc/sba_iommu.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/parisc/sba_iommu.c	Sat Apr  3 19:38:54 2004
@@ -700,7 +700,8 @@
 
 
 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 @@
 
 	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 @@
 */
 #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 @@
 	** 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 @@
 	** 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 @@
 	.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 @@
 	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 -Nru a/drivers/parisc/superio.c b/drivers/parisc/superio.c
--- a/drivers/parisc/superio.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/parisc/superio.c	Sat Apr  3 19:38:45 2004
@@ -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 @@
 	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 @@
 }
 
 
-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);
 }
 
-EXPORT_SYMBOL(superio_get_ide_irq);
+/* 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);
+}
+
+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 -Nru a/drivers/parport/daisy.c b/drivers/parport/daisy.c
--- a/drivers/parport/daisy.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/parport/daisy.c	Sat Apr  3 19:38:42 2004
@@ -27,7 +27,7 @@
 #include <asm/current.h>
 #include <asm/uaccess.h>
 
-#define DEBUG /* undef me for production */
+#undef DEBUG
 
 #ifdef DEBUG
 #define DPRINTK(stuff...) printk (stuff)
diff -Nru a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
--- a/drivers/parport/parport_gsc.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/parport/parport_gsc.c	Sat Apr  3 19:38:55 2004
@@ -476,7 +476,7 @@
 	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 @@
 		parport_put_port(p);
 		kfree (ops); /* hope no-one cached it */
 	}
+	return 0;
 }
 
 static struct parisc_device_id parport_tbl[] = {
@@ -508,7 +509,7 @@
 	.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 -Nru a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
--- a/drivers/parport/parport_pc.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/parport/parport_pc.c	Sat Apr  3 19:38:56 2004
@@ -13,6 +13,7 @@
  * Many ECP bugs fixed.  Fred Barnes & Jamie Lokier, 1999
  * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. 
  * Various hacks, Fred Barnes, 04/2001
+ * Updated probing logic - Adam Belay <ambx1@neo.rr.com>
  */
 
 /* This driver should work with any hardware that is broadly compatible
@@ -98,7 +99,8 @@
        (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO))
 static int verbose_probing;
 #endif
-static int registered_parport;
+static int pci_registered_parport;
+static int pnp_registered_parport;
 
 /* frob_control, but for ECR */
 static void frob_econtrol (struct parport *pb, unsigned char m,
@@ -2771,10 +2773,11 @@
 };
 MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
 
-static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
+static int parport_pc_pci_probe (struct pci_dev *dev,
 					   const struct pci_device_id *id)
 {
 	int err, count, n, i = id->driver_data;
+
 	if (i < last_sio)
 		/* This is an onboard Super-IO and has already been probed */
 		return 0;
@@ -2847,23 +2850,72 @@
 static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;}
 #endif /* CONFIG_PCI */
 
-#ifdef CONFIG_PNP
-static const struct pnp_device_id pnp_dev_table[] = {
+
+static const struct pnp_device_id parport_pc_pnp_tbl[] = {
 	/* Standard LPT Printer Port */
 	{.id = "PNP0400", .driver_data = 0},
 	/* ECP Printer Port */
 	{.id = "PNP0401", .driver_data = 0},
-	{.id = ""}
+	{ }
 };
 
+MODULE_DEVICE_TABLE(pnp,parport_pc_pnp_tbl);
+
+static int parport_pc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
+{
+	struct parport *pdata;
+	unsigned long io_lo, io_hi;
+	int dma, irq;
+
+	if (pnp_port_valid(dev,0) &&
+		!(pnp_port_flags(dev,0) & IORESOURCE_DISABLED)) {
+		io_lo = pnp_port_start(dev,0);
+	} else
+		return -EINVAL;
+
+	if (pnp_port_valid(dev,1) &&
+		!(pnp_port_flags(dev,1) & IORESOURCE_DISABLED)) {
+		io_hi = pnp_port_start(dev,1);
+	} else
+		io_hi = 0;
+
+	if (pnp_irq_valid(dev,0) &&
+		!(pnp_irq_flags(dev,0) & IORESOURCE_DISABLED)) {
+		irq = pnp_irq(dev,0);
+	} else
+		irq = PARPORT_IRQ_NONE;
+
+	if (pnp_dma_valid(dev,0) &&
+		!(pnp_dma_flags(dev,0) & IORESOURCE_DISABLED)) {
+		dma = pnp_dma(dev,0);
+	} else
+		dma = PARPORT_DMA_NONE;
+
+	printk(KERN_INFO "parport: PnPBIOS parport detected.\n");
+	if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, NULL)))
+		return -ENODEV;
+
+	pnp_set_drvdata(dev,pdata);
+	return 0;
+}
+
+static void parport_pc_pnp_remove(struct pnp_dev *dev)
+{
+	struct parport *pdata = (struct parport *)pnp_get_drvdata(dev);
+	if (!pdata)
+		return;
+
+	parport_pc_unregister_port(pdata);
+}
+
 /* we only need the pnp layer to activate the device, at least for now */
 static struct pnp_driver parport_pc_pnp_driver = {
 	.name		= "parport_pc",
-	.id_table	= pnp_dev_table,
+	.id_table	= parport_pc_pnp_tbl,
+	.probe		= parport_pc_pnp_probe,
+	.remove		= parport_pc_pnp_remove,
 };
-#else
-static struct pnp_driver parport_pc_pnp_driver;
-#endif
+
 
 /* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
 static int __init __attribute__((unused))
@@ -2903,12 +2955,18 @@
 	/* Onboard SuperIO chipsets that show themselves on the PCI bus. */
 	count += parport_pc_init_superio (autoirq, autodma);
 
+	r = pnp_register_driver (&parport_pc_pnp_driver);
+	if (r >= 0) {
+		pnp_registered_parport = 1;
+		count += r;
+	}
+
 	/* ISA ports and whatever (see asm/parport.h). */
 	count += parport_pc_find_nonpci_ports (autoirq, autodma);
 
 	r = pci_register_driver (&parport_pc_pci_driver);
 	if (r >= 0) {
-		registered_parport = 1;
+		pci_registered_parport = 1;
 		count += r;
 	}
 
@@ -3104,9 +3162,6 @@
 	if (parse_parport_params())
 		return -EINVAL;
 
-	/* try to activate any PnP parports first */
-	pnp_register_driver(&parport_pc_pnp_driver);
-
 	if (io[0]) {
 		int i;
 		/* Only probe the ports we were given. */
@@ -3120,24 +3175,18 @@
 						  irqval[i], dmaval[i], NULL))
 				count++;
 		}
-	} else {
+	} else
 		count += parport_pc_find_ports (irqval[0], dmaval[0]);
-		if (!count && registered_parport)
-			pci_unregister_driver (&parport_pc_pci_driver);
-	}
-
-	if (!count) {
-		pnp_unregister_driver (&parport_pc_pnp_driver);
-		return -ENODEV;
-	}
 
 	return 0;
 }
 
 static void __exit parport_pc_exit(void)
 {
-	if (registered_parport)
+	if (pci_registered_parport)
 		pci_unregister_driver (&parport_pc_pci_driver);
+	if (pnp_registered_parport)
+		pnp_unregister_driver (&parport_pc_pnp_driver);
 
 	spin_lock(&ports_lock);
 	while (!list_empty(&ports_list)) {
@@ -3151,13 +3200,8 @@
 		spin_lock(&ports_lock);
 	}
 	spin_unlock(&ports_lock);
-	pnp_unregister_driver (&parport_pc_pnp_driver);
 }
 
-
-MODULE_AUTHOR("Phil Blundell, Tim Waugh, others");
-MODULE_DESCRIPTION("PC-style parallel port driver");
-MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Phil Blundell, Tim Waugh, others");
 MODULE_DESCRIPTION("PC-style parallel port driver");
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
--- a/drivers/pci/hotplug/Makefile	Sat Apr  3 19:38:54 2004
+++ b/drivers/pci/hotplug/Makefile	Sat Apr  3 19:38:54 2004
@@ -40,7 +40,9 @@
 				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 -Nru a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
--- a/drivers/pci/hotplug/acpiphp.h	Sat Apr  3 19:38:56 2004
+++ b/drivers/pci/hotplug/acpiphp.h	Sat Apr  3 19:38:56 2004
@@ -235,7 +235,7 @@
 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 -Nru a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
--- a/drivers/pci/hotplug/acpiphp_glue.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/pci/hotplug/acpiphp_glue.c	Sat Apr  3 19:38:42 2004
@@ -694,14 +694,14 @@
 		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 @@
 				warn("%s: _PS3 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -757,7 +758,8 @@
 				warn("%s: _EJ0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
-			}
+			} else
+				break;
 		}
 	}
 
@@ -865,15 +867,8 @@
 	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 @@
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
-				enabled++;
+				disabled++;
 			}
 		} else {
 			/* if disabled but present, enable */
@@ -1280,7 +1275,7 @@
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
-				disabled++;
+				enabled++;
 			}
 		}
 	}
diff -Nru a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c
--- a/drivers/pci/hotplug/acpiphp_pci.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/pci/hotplug/acpiphp_pci.c	Sat Apr  3 19:38:40 2004
@@ -83,8 +83,8 @@
 		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 @@
 		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 @@
 		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 @@
  * @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 @@
 	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 -Nru a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c
--- a/drivers/pci/hotplug/acpiphp_res.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/pci/hotplug/acpiphp_res.c	Sat Apr  3 19:38:42 2004
@@ -224,7 +224,7 @@
 		}  /* 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 -Nru a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
--- a/drivers/pci/hotplug/cpqphp_core.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/pci/hotplug/cpqphp_core.c	Sat Apr  3 19:38:40 2004
@@ -1342,7 +1342,7 @@
 	cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN);
 	if (!cpqhp_rom_start) {
 		err ("Could not ioremap memory region for ROM\n");
-		retval = -EIO;;
+		retval = -EIO;
 		goto error;
 	}
 	
@@ -1353,14 +1353,14 @@
 	smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN);
 	if (!smbios_table) {
 		err ("Could not find the SMBIOS pointer in memory\n");
-		retval = -EIO;;
+		retval = -EIO;
 		goto error;
 	}
 
 	smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), readw(smbios_table + ST_LENGTH));
 	if (!smbios_start) {
 		err ("Could not ioremap memory region taken from SMBIOS values\n");
-		retval = -EIO;;
+		retval = -EIO;
 		goto error;
 	}
 
diff -Nru a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
--- a/drivers/pci/hotplug/pci_hotplug_core.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/pci/hotplug/pci_hotplug_core.c	Sat Apr  3 19:38:55 2004
@@ -104,19 +104,7 @@
 	.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 -Nru a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
--- a/drivers/pci/hotplug/pciehp_hpc.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/pci/hotplug/pciehp_hpc.c	Sat Apr  3 19:38:44 2004
@@ -915,7 +915,7 @@
 		rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
 		if (rc) {
 			err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
-			return IRQ_NONE;;
+			return IRQ_NONE;
 		}
 
 		temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x00;
@@ -923,7 +923,7 @@
 		rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
 		if (rc) {
 			err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
-			return IRQ_NONE;;
+			return IRQ_NONE;
 		}
 	}
 	
diff -Nru a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
--- a/drivers/pci/hotplug/pciehp_pci.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/pci/hotplug/pciehp_pci.c	Sat Apr  3 19:38:55 2004
@@ -103,7 +103,7 @@
  */
 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 -Nru a/drivers/pci/hotplug/pciehprm_acpi.c b/drivers/pci/hotplug/pciehprm_acpi.c
--- a/drivers/pci/hotplug/pciehprm_acpi.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/pci/hotplug/pciehprm_acpi.c	Sat Apr  3 19:38:55 2004
@@ -1268,7 +1268,8 @@
 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 -Nru a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
--- a/drivers/pci/hotplug/rpadlpar_core.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/pci/hotplug/rpadlpar_core.c	Sat Apr  3 19:38:44 2004
@@ -43,7 +43,28 @@
 	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 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 @@
 	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 @@
 		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 @@
 
 	if (!bridge_dev) {
 		printk(KERN_ERR "%s: unexpected null device\n",
-				__FUNCTION__);
+			__FUNCTION__);
 		return 1;
 	}
 
@@ -188,11 +209,25 @@
 
 	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 @@
  */
 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 @@
 }
 
 /**
- * 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 @@
 
 	if (!is_dlpar_capable()) {
 		printk(KERN_WARNING "%s: partition not DLPAR capable\n",
-				__FUNCTION__);
+			__FUNCTION__);
 		return -EPERM;
 	}
 
diff -Nru a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
--- a/drivers/pci/hotplug/rpaphp.h	Sat Apr  3 19:38:42 2004
+++ b/drivers/pci/hotplug/rpaphp.h	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
--- a/drivers/pci/hotplug/rpaphp_core.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/pci/hotplug/rpaphp_core.c	Sat Apr  3 19:38:56 2004
@@ -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 @@
 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 @@
  * 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 @@
 
 	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 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 @@
 	down(&rpaphp_sem);
 	retval = rpaphp_get_power_status(slot, value);
 	up(&rpaphp_sem);
-
 	return retval;
 }
 
@@ -231,7 +152,7 @@
  *
  *
  */
-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 @@
 	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 @@
 		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 @@
 		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 @@
  * 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 @@
 	/*
 	 * 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 -Nru a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
--- a/drivers/pci/hotplug/rpaphp_pci.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/pci/hotplug/rpaphp_pci.c	Sat Apr  3 19:38:40 2004
@@ -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,335 @@
 
 	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);
+		eeh_add_device(dev);
+	} 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 */
+	eeh_remove_device(slot->dev.pci_dev);
+	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 -Nru a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/hotplug/rpaphp_slot.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/pci/hotplug/rpaphp_vio.c b/drivers/pci/hotplug/rpaphp_vio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/pci/hotplug/rpaphp_vio.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/pci/hotplug/shpchp_pci.c b/drivers/pci/hotplug/shpchp_pci.c
--- a/drivers/pci/hotplug/shpchp_pci.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/pci/hotplug/shpchp_pci.c	Sat Apr  3 19:38:43 2004
@@ -101,7 +101,7 @@
  */
 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 -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/pci/pci.c	Sat Apr  3 19:38:42 2004
@@ -686,7 +686,7 @@
 	if (!pci_dma_supported(dev, mask))
 		return -EIO;
 
-	dev->consistent_dma_mask = mask;
+	dev->dev.coherent_dma_mask = mask;
 
 	return 0;
 }
diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c
--- a/drivers/pci/probe.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/pci/probe.c	Sat Apr  3 19:38:54 2004
@@ -570,7 +570,6 @@
 	/* 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_name_device(dev);
 
 	dev->dev.dma_mask = &dev->dma_mask;
+	dev->dev.coherent_dma_mask = 0xffffffffull;
 
 	return dev;
 }
diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c
--- a/drivers/pci/quirks.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/pci/quirks.c	Sat Apr  3 19:38:40 2004
@@ -760,7 +760,7 @@
 
 #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 @@
 	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 @@
 	{ 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 -Nru a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
--- a/drivers/pci/setup-res.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/pci/setup-res.c	Sat Apr  3 19:38:55 2004
@@ -94,13 +94,18 @@
 pci_claim_resource(struct pci_dev *dev, int resource)
 {
 	struct resource *res = &dev->resource[resource];
-	struct resource *root = pci_find_parent_resource(dev, res);
+	struct resource *root = NULL;
 	char *dtype = resource < PCI_BRIDGE_RESOURCES ? "device" : "bridge";
 	int err;
 
+	if (res->flags & IORESOURCE_IO)
+		root = &ioport_resource;
+	if (res->flags & IORESOURCE_MEM)
+		root = &iomem_resource;
+
 	err = -EINVAL;
 	if (root != NULL)
-		err = request_resource(root, res);
+		err = insert_resource(root, res);
 
 	if (err) {
 		printk(KERN_ERR "PCI: %s region %d of %s %s [%lx:%lx]\n",
diff -Nru a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
--- a/drivers/pcmcia/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/drivers/pcmcia/Kconfig	Sat Apr  3 19:38:54 2004
@@ -26,6 +26,25 @@
 	  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 -Nru a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
--- a/drivers/pcmcia/Makefile	Sat Apr  3 19:38:55 2004
+++ b/drivers/pcmcia/Makefile	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
--- a/drivers/pcmcia/au1000_generic.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/pcmcia/au1000_generic.c	Sat Apr  3 19:38:44 2004
@@ -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 @@
 	 */
 	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 @@
 		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 @@
 	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 @@
 
 	*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 @@
 {
 	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 @@
 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 @@
 	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 @@
 	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 -Nru a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
--- a/drivers/pcmcia/au1000_pb1x00.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/pcmcia/au1000_pb1x00.c	Sat Apr  3 19:38:42 2004
@@ -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 @@
 	}
 
 	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 @@
 
 	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 -Nru a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c
--- a/drivers/pcmcia/bulkmem.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/pcmcia/bulkmem.c	Sat Apr  3 19:38:57 2004
@@ -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 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 @@
     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 @@
     }
 } /* 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 @@
 
 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 @@
     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 @@
     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 @@
 	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 @@
     }
     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_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 -Nru a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
--- a/drivers/pcmcia/cardbus.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/pcmcia/cardbus.c	Sat Apr  3 19:38:42 2004
@@ -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 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 @@
 	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 -Nru a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
--- a/drivers/pcmcia/cistpl.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/pcmcia/cistpl.c	Sat Apr  3 19:38:42 2004
@@ -143,7 +143,7 @@
 {
     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 @@
 	    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 @@
 {
     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 @@
 	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 -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
--- a/drivers/pcmcia/cs.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/pcmcia/cs.c	Sat Apr  3 19:38:42 2004
@@ -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 @@
 /* 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 @@
 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 @@
 	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 @@
 	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 @@
 {
     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 @@
 {
     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 @@
     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_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 @@
 {
 	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 @@
 		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 @@
 {
 	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 @@
 	}
 
 	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 @@
 	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 @@
 
 	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 @@
 {
 	int ret;
 
+	cs_dbg(skt, 4, "insert\n");
+
 	if (!cs_socket_get(skt))
 		return CS_NO_CARD;
 
@@ -667,6 +572,8 @@
 			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 @@
  */
 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 @@
     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 @@
     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 @@
     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 @@
 	    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 @@
 	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 @@
     
 	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_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 @@
 	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_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 @@
 	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 @@
     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 @@
 /* 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_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 @@
 {
     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 -Nru a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
--- a/drivers/pcmcia/cs_internal.h	Sat Apr  3 19:38:57 2004
+++ b/drivers/pcmcia/cs_internal.h	Sat Apr  3 19:38:57 2004
@@ -167,7 +167,6 @@
 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 @@
 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 -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
--- a/drivers/pcmcia/ds.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/pcmcia/ds.c	Sat Apr  3 19:38:54 2004
@@ -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_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_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 @@
 
 /*====================================================================*/
 
+/* 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 @@
 {
     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 @@
 {
     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 @@
 {
     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 @@
     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 @@
 {
     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 @@
     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 @@
     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 @@
     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 @@
 
     /* 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 @@
     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 @@
 	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 @@
     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 @@
 	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 @@
     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 @@
     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 @@
     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 @@
 	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 @@
     }
     
     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 @@
 
 	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 -Nru a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
--- a/drivers/pcmcia/i82365.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/pcmcia/i82365.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 {
     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 @@
     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 @@
 
     /* 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 @@
     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 @@
 		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 @@
     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 @@
 	}
     }
     
-    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 @@
 	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 @@
     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 @@
 {
     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 @@
     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 -Nru a/drivers/pcmcia/sa1100_pangolin.c b/drivers/pcmcia/sa1100_pangolin.c
--- a/drivers/pcmcia/sa1100_pangolin.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/pcmcia/sa1100_pangolin.c	Sat Apr  3 19:38:41 2004
@@ -54,7 +54,7 @@
 pangolin_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt,
 			     struct pcmcia_state *state)
 {
-	unsigned long levels = GPLR;;
+	unsigned long levels = GPLR;
 
 	state->detect=((levels & GPIO_PCMCIA_CD)==0)?1:0;
 	state->ready=(levels & GPIO_PCMCIA_IRQ)?1:0;
diff -Nru a/drivers/pcmcia/sa11xx_core.c b/drivers/pcmcia/sa11xx_core.c
--- a/drivers/pcmcia/sa11xx_core.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/pcmcia/sa11xx_core.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 
 	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 @@
 {
 	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 @@
 	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 @@
 {
 	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 @@
 		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_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 @@
 {
 	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 @@
 {
   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 @@
 {
   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 @@
 	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 @@
 	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 @@
 
 	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 -Nru a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
--- a/drivers/pcmcia/tcic.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/pcmcia/tcic.c	Sat Apr  3 19:38:44 2004
@@ -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 @@
    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_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 @@
     } 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 @@
     }
     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 @@
     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 @@
 	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 @@
     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 @@
     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 @@
     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 -Nru a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
--- a/drivers/pcmcia/yenta_socket.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/pcmcia/yenta_socket.c	Sat Apr  3 19:38:44 2004
@@ -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 @@
 {
 	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 @@
 {
 	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 @@
 {
 	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 @@
 	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);
 }
@@ -1016,6 +1016,11 @@
 
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250, TI1250),
 	CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1410, TI1250),
+
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1211, TI12XX),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, TI12XX),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, TI1250),
+	CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, TI12XX),
 
 	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH),
 	CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH),
diff -Nru a/drivers/pnp/isapnp/Kconfig b/drivers/pnp/isapnp/Kconfig
--- a/drivers/pnp/isapnp/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/drivers/pnp/isapnp/Kconfig	Sat Apr  3 19:38:43 2004
@@ -2,8 +2,8 @@
 # ISA Plug and Play configuration
 #
 config ISAPNP
-	bool "ISA Plug and Play support (EXPERIMENTAL)"
-	depends on PNP && EXPERIMENTAL
+	bool "ISA Plug and Play support"
+	depends on PNP
 	help
 	  Say Y here if you would like support for ISA Plug and Play devices.
 	  Some information is in <file:Documentation/isapnp.txt>.
diff -Nru a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
--- a/drivers/pnp/isapnp/core.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/pnp/isapnp/core.c	Sat Apr  3 19:38:43 2004
@@ -99,6 +99,7 @@
 static unsigned char isapnp_checksum_value;
 static DECLARE_MUTEX(isapnp_cfg_mutex);
 static int isapnp_detected;
+static int isapnp_csn_count;
 
 /* some prototypes */
 
@@ -371,11 +372,14 @@
 			break;
 		}
 	      __next:
+		if (csn == 255)
+			break;
 		checksum = 0x6a;
 		chksum = 0x00;
 		bit = 0x00;
 	}
 	isapnp_wait();
+	isapnp_csn_count = csn;
 	return csn;
 }
 
@@ -880,7 +884,7 @@
 
 	isapnp_wait();
 	isapnp_key();
-	for (csn = 1; csn <= 10; csn++) {
+	for (csn = 1; csn <= isapnp_csn_count; csn++) {
 		isapnp_wake(csn);
 		isapnp_peek(header, 9);
 		checksum = isapnp_checksum(header);
@@ -890,12 +894,6 @@
 			header[4], header[5], header[6], header[7], header[8]);
 		printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
 #endif
-		/* Don't be strict on the checksum, here !
-                   e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7)*/
-		if (header[8] == 0)
-			;
-		else if (checksum == 0x00 || checksum != header[8])	/* not valid CSN */
-			continue;
 		if ((card = isapnp_alloc(sizeof(struct pnp_card))) == NULL)
 			continue;
 
@@ -932,9 +930,8 @@
 
 int isapnp_cfg_begin(int csn, int logdev)
 {
-	if (csn < 1 || csn > 10 || logdev > 10)
+	if (csn < 1 || csn > isapnp_csn_count || logdev > 10)
 		return -EINVAL;
-	MOD_INC_USE_COUNT;
 	down(&isapnp_cfg_mutex);
 	isapnp_wait();
 	isapnp_key();
@@ -962,7 +959,6 @@
 {
 	isapnp_wait();
 	up(&isapnp_cfg_mutex);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1050,7 +1046,7 @@
 	for (tmp = 0; tmp < PNP_MAX_DMA && (res->dma_resource[tmp].flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; tmp++)
 		isapnp_write_byte(ISAPNP_CFG_DMA+tmp, res->dma_resource[tmp].start);
 	for (tmp = 0; tmp < PNP_MAX_MEM && (res->mem_resource[tmp].flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; tmp++)
-		isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<2), (res->mem_resource[tmp].start >> 8) & 0xffff);
+		isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<3), (res->mem_resource[tmp].start >> 8) & 0xffff);
 	/* FIXME: We aren't handling 32bit mems properly here */
 	isapnp_activate(dev->number);
 	isapnp_cfg_end();
diff -Nru a/drivers/pnp/resource.c b/drivers/pnp/resource.c
--- a/drivers/pnp/resource.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/pnp/resource.c	Sat Apr  3 19:38:44 2004
@@ -231,15 +231,9 @@
 
 #define length(start, end) (*(end) - *(start) + 1)
 
-/* ranged_conflict - used to determine if two resource ranges conflict
- * condition 1: check if the start of a is within b
- * condition 2: check if the end of a is within b
- * condition 3: check if b is engulfed by a */
-
+/* Two ranges conflict if one doesn't end before the other starts */
 #define ranged_conflict(starta, enda, startb, endb) \
-((*(starta) >= *(startb) && *(starta) <= *(endb)) || \
- (*(enda) >= *(startb) && *(enda) <= *(endb)) || \
- (*(starta) < *(startb) && *(enda) > *(endb)))
+	!((*(enda) < *(startb)) || (*(endb) < *(starta)))
 
 #define cannot_compare(flags) \
 ((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
diff -Nru a/drivers/pnp/system.c b/drivers/pnp/system.c
--- a/drivers/pnp/system.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/pnp/system.c	Sat Apr  3 19:38:57 2004
@@ -21,7 +21,7 @@
 	{	"",			0	}
 };
 
-static void __init reserve_ioport_range(char *pnpid, int start, int end)
+static void reserve_ioport_range(char *pnpid, int start, int end)
 {
 	struct resource *res;
 	char *regionid;
@@ -49,7 +49,7 @@
 	return;
 }
 
-static void __init reserve_resources_of_dev( struct pnp_dev *dev )
+static void reserve_resources_of_dev( struct pnp_dev *dev )
 {
 	int i;
 
diff -Nru a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
--- a/drivers/s390/block/Kconfig	Sat Apr  3 19:38:40 2004
+++ b/drivers/s390/block/Kconfig	Sat Apr  3 19:38:40 2004
@@ -48,12 +48,12 @@
 	  say "Y".
 
 config DASD_DIAG
-	tristate "Support for DIAG access to CMS reserved Disks"
+	tristate "Support for DIAG access to Disks"
 	depends on DASD && ARCH_S390X = 'n'
 	help
-	  Select this option if you want to use CMS reserved Disks under VM
-	  with the Diagnose250 command.  If you are not running under VM or
-	  unsure what it is, say "N".
+	  Select this option if you want to use Diagnose250 command to access
+	  Disks under VM.  If you are not running under VM or unsure what it is,
+	  say "N".
 
 config DASD_CMB
 	tristate "Compatibility interface for DASD channel measurement blocks"
diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/s390/block/dasd.c	Sat Apr  3 19:38:43 2004
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
- * $Revision: 1.129 $
+ * $Revision: 1.136 $
  */
 
 #include <linux/config.h>
@@ -224,7 +224,8 @@
 		return rc;
 	dasd_setup_queue(device);
 	device->state = DASD_STATE_READY;
-	dasd_scan_partitions(device);
+	if (dasd_scan_partitions(device) != 0)
+		device->state = DASD_STATE_BASIC;
 	return 0;
 }
 
@@ -687,7 +688,10 @@
 		rc = ccw_device_clear(device->cdev, (long) cqr);
 		switch (rc) {
 		case 0:	/* termination successful */
-			cqr->status = DASD_CQR_FAILED;
+			if (cqr->retries > 0)
+				cqr->status = DASD_CQR_QUEUED;
+			else
+				cqr->status = DASD_CQR_FAILED;
 			cqr->stopclk = get_clock();
 			break;
 		case -ENODEV:
@@ -779,7 +783,7 @@
 
 	device = (struct dasd_device *) ptr;
 	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
-	/* re-activate first request in queue */
+	/* re-activate request queue */
         device->stopped &= ~DASD_STOPPED_PENDING;
 	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
 	dasd_schedule_bh(device);
@@ -827,12 +831,25 @@
 		struct dasd_device *device;
 	} *p;
 	struct dasd_device *device;
+	struct dasd_ccw_req *cqr;
+	struct list_head *l, *n;
+	unsigned long flags;
 
 	p = data;
 	device = p->device;
 	DBF_EVENT(DBF_NOTICE, "State change Interrupt for bus_id %s",
 		  device->cdev->dev.bus_id);
 	device->stopped &= ~DASD_STOPPED_PENDING;
+
+        /* restart all 'running' IO on queue */
+	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+	list_for_each_safe(l, n, &device->ccw_queue) {
+		cqr = list_entry(l, struct dasd_ccw_req, list);
+                if (cqr->status == DASD_CQR_IN_IO)
+                        cqr->status = DASD_CQR_QUEUED;
+        }
+	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+	dasd_set_timer (device, 0);
 	dasd_schedule_bh(device);
 	dasd_put_device(device);
 	kfree(p);
@@ -847,7 +864,8 @@
 	cqr = (struct dasd_ccw_req *) intparm;
 	if (cqr->status != DASD_CQR_IN_IO) {
 		MESSAGE(KERN_DEBUG,
-			"invalid status: bus_id %s, status %02x",
+			"invalid status in handle_killed_request: "
+			"bus_id %s, status %02x",
 			cdev->dev.bus_id, cqr->status);
 		return;
 	}
@@ -1142,7 +1160,8 @@
 	       elv_next_request(queue) &&
 		nr_queued < DASD_CHANQ_MAX_SIZE) {
 		req = elv_next_request(queue);
-		if (device->ro_flag && rq_data_dir(req) == WRITE) {
+		if (test_bit(DASD_FLAG_RO, &device->flags) &&
+		    rq_data_dir(req) == WRITE) {
 			DBF_EVENT(DBF_ERR,
 				  "(%s) Rejecting write request %p",
 				  device->cdev->dev.bus_id,
@@ -1186,13 +1205,11 @@
 __dasd_check_expire(struct dasd_device * device)
 {
 	struct dasd_ccw_req *cqr;
-	unsigned long long now;
 
 	if (list_empty(&device->ccw_queue))
 		return;
 	cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
 	if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) {
-		now = get_clock();
 		if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) {
 			if (device->discipline->term_IO(cqr) != 0)
 				/* Hmpf, try again in 1/100 sec */
@@ -1517,7 +1534,8 @@
  * terminated if it is currently in i/o.
  * Returns 1 if the request has been terminated.
  */
-int dasd_cancel_req(struct dasd_ccw_req *cqr)
+int
+dasd_cancel_req(struct dasd_ccw_req *cqr)
 {
 	struct dasd_device *device = cqr->device;
 	unsigned long flags;
@@ -1657,9 +1675,17 @@
 	struct dasd_device *device = disk->private_data;
 	int rc;
 
-	if (!try_module_get(device->discipline->owner))
-		return -EINVAL;
-	
+        atomic_inc(&device->open_count);
+	if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
+		rc = -ENODEV;
+		goto unlock;
+	}
+
+	if (!try_module_get(device->discipline->owner)) {
+		rc = -EINVAL;
+		goto unlock;
+	}
+
 	if (dasd_probeonly) {
 		MESSAGE(KERN_INFO,
 			"No access to device %s due to probeonly mode",
@@ -1668,7 +1694,6 @@
 		goto out;
 	}
 
-	rc = -ENODEV;
 	if (device->state < DASD_STATE_BASIC) {
 		DBF_DEV_EVENT(DBF_ERR, device, " %s",
 			      " Cannot open unrecognized device");
@@ -1676,11 +1701,12 @@
 		goto out;
 	}
 
-	atomic_inc(&device->open_count);
 	return 0;
 
 out:
 	module_put(device->discipline->owner);
+unlock:
+	atomic_dec(&device->open_count);
 	return rc;
 }
 
@@ -1690,12 +1716,6 @@
 	struct gendisk *disk = inp->i_bdev->bd_disk;
 	struct dasd_device *device = disk->private_data;
 
-	if (device->state < DASD_STATE_BASIC) {
-		DBF_DEV_EVENT(DBF_ERR, device, " %s",
-			      " Cannot release unrecognized device");
-		return -EINVAL;
-	}
-
 	atomic_dec(&device->open_count);
 	module_put(device->discipline->owner);
 	return 0;
@@ -1741,7 +1761,7 @@
 	ret = dasd_add_sysfs_files(cdev);
 	if (ret) {
 		printk(KERN_WARNING
-		       "dasd_generic_probe: could not add driverfs entries"
+		       "dasd_generic_probe: could not add sysfs entries "
 		       "for %s\n", cdev->dev.bus_id);
 	}
 
@@ -1757,12 +1777,23 @@
 {
 	struct dasd_device *device;
 
+	dasd_remove_sysfs_files(cdev);
 	device = dasd_device_from_cdev(cdev);
-	if (!IS_ERR(device)) {
-		dasd_set_target_state(device, DASD_STATE_NEW);
-		/* dasd_delete_device destroys the device reference. */
-		dasd_delete_device(device);
+	if (IS_ERR(device))
+		return;
+	if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) {
+		/* Already doing offline processing */
+		dasd_put_device(device);
+		return;
 	}
+	/*
+	 * This device is removed unconditionally. Set offline
+	 * flag to prevent dasd_open from opening it while it is
+	 * no quite down yet.
+	 */
+	dasd_set_target_state(device, DASD_STATE_NEW);
+	/* dasd_delete_device destroys the device reference. */
+	dasd_delete_device(device);
 }
 
 /* activate a device. This is called from dasd_{eckd,fba}_probe() when either
@@ -1780,7 +1811,7 @@
 	if (IS_ERR(device))
 		return PTR_ERR(device);
 
-	if (device->use_diag_flag) {
+	if (test_bit(DASD_FLAG_USE_DIAG, &device->flags)) {
 	  	if (!dasd_diag_discipline_pointer) {
 		        printk (KERN_WARNING
 				"dasd_generic couldn't online device %s "
@@ -1828,17 +1859,35 @@
 dasd_generic_set_offline (struct ccw_device *cdev)
 {
 	struct dasd_device *device;
+	int max_count;
 
 	device = dasd_device_from_cdev(cdev);
-	if (atomic_read(&device->open_count) > 0) {
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) {
+		/* Already doing offline processing */
+		dasd_put_device(device);
+		return 0;
+	}
+	/*
+	 * We must make sure that this device is currently not in use.
+	 * The open_count is increased for every opener, that includes
+	 * the blkdev_get in dasd_scan_partitions. We are only interested
+	 * in the other openers.
+	 */
+	max_count = device->bdev ? 1 : 0;
+	if (atomic_read(&device->open_count) > max_count) {
 		printk (KERN_WARNING "Can't offline dasd device with open"
 			" count = %i.\n",
 			atomic_read(&device->open_count));
+		clear_bit(DASD_FLAG_OFFLINE, &device->flags);
 		dasd_put_device(device);
 		return -EBUSY;
 	}
-	dasd_put_device(device);
-	dasd_generic_remove (cdev);
+	dasd_set_target_state(device, DASD_STATE_NEW);
+	/* dasd_delete_device destroys the device reference. */
+	dasd_delete_device(device);
+
 	return 0;
 }
 
@@ -1861,7 +1910,7 @@
 		if (device->state < DASD_STATE_BASIC)
 			break;
 		/* Device is active. We want to keep it. */
-		if (device->disconnect_error_flag) {
+		if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) {
 			list_for_each_entry(cqr, &device->ccw_queue, list)
 				if (cqr->status == DASD_CQR_IN_IO)
 					cqr->status = DASD_CQR_FAILED;
diff -Nru a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
--- a/drivers/s390/block/dasd_3990_erp.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/s390/block/dasd_3990_erp.c	Sat Apr  3 19:38:55 2004
@@ -5,7 +5,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
  *
- * $Revision: 1.27 $
+ * $Revision: 1.28 $
  */
 
 #include <linux/timer.h>
@@ -229,7 +229,7 @@
 	struct dasd_device *device = erp->device;
 
 	DEV_MESSAGE(KERN_INFO, device,
-		    "blocking request queue for %is", expires);
+		    "blocking request queue for %is", expires/HZ);
 
 	device->stopped |= DASD_STOPPED_PENDING;
 	erp->status = DASD_CQR_QUEUED;
@@ -2623,7 +2623,7 @@
 
 #ifdef ERP_DEBUG
 	/* print current erp_chain */
-	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+	DEV_MESSAGE(KERN_ERR, device, "%s",
 		    "ERP chain at BEGINNING of ERP-ACTION");
 	{
 		struct dasd_ccw_req *temp_erp = NULL;
@@ -2631,9 +2631,10 @@
 		for (temp_erp = cqr;
 		     temp_erp != NULL; temp_erp = temp_erp->refers) {
 
-			DEV_MESSAGE(KERN_DEBUG, device,
-				    "	   erp %p refers to %p",
-				    temp_erp, temp_erp->refers);
+			DEV_MESSAGE(KERN_ERR, device,
+				    "   erp %p (%02x) refers to %p",
+				    temp_erp, temp_erp->status,
+				    temp_erp->refers);
 		}
 	}
 #endif				/* ERP_DEBUG */
@@ -2675,15 +2676,16 @@
 
 #ifdef ERP_DEBUG
 	/* print current erp_chain */
-	DEV_MESSAGE(KERN_DEBUG, device, "%s", "ERP chain at END of ERP-ACTION");
+	DEV_MESSAGE(KERN_ERR, device, "%s", "ERP chain at END of ERP-ACTION");
 	{
 		struct dasd_ccw_req *temp_erp = NULL;
 		for (temp_erp = erp;
 		     temp_erp != NULL; temp_erp = temp_erp->refers) {
 
-			DEV_MESSAGE(KERN_DEBUG, device,
-				    "	   erp %p refers to %p",
-				    temp_erp, temp_erp->refers);
+			DEV_MESSAGE(KERN_ERR, device,
+				    "   erp %p (%02x) refers to %p",
+				    temp_erp, temp_erp->status,
+				    temp_erp->refers);
 		}
 	}
 #endif				/* ERP_DEBUG */
diff -Nru a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
--- a/drivers/s390/block/dasd_devmap.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/s390/block/dasd_devmap.c	Sat Apr  3 19:38:43 2004
@@ -11,7 +11,7 @@
  * functions may not be called from interrupt context. In particular
  * dasd_get_device is a no-no from interrupt context.
  *
- * $Revision: 1.25 $
+ * $Revision: 1.27 $
  */
 
 #include <linux/config.h>
@@ -466,10 +466,14 @@
 	if (!devmap->device) {
 		devmap->device = device;
 		device->devindex = devmap->devindex;
-		device->ro_flag = 
-			(devmap->features & DASD_FEATURE_READONLY) != 0;
-		device->use_diag_flag = 
-			(devmap->features & DASD_FEATURE_USEDIAG) != 0;
+		if (devmap->features & DASD_FEATURE_READONLY)
+			set_bit(DASD_FLAG_RO, &device->flags);
+		else
+			clear_bit(DASD_FLAG_RO, &device->flags);
+		if (devmap->features & DASD_FEATURE_USEDIAG)
+			set_bit(DASD_FLAG_USE_DIAG, &device->flags);
+		else
+			clear_bit(DASD_FLAG_USE_DIAG, &device->flags);
 		get_device(&cdev->dev);
 		device->cdev = cdev;
 		rc = 0;
@@ -596,7 +600,10 @@
 	if (devmap->device) {
 		if (devmap->device->gdp)
 			set_disk_ro(devmap->device->gdp, ro_flag);
-		devmap->device->ro_flag = ro_flag;
+		if (ro_flag)
+			set_bit(DASD_FLAG_RO, &devmap->device->flags);
+		else
+			clear_bit(DASD_FLAG_RO, &devmap->device->flags);
 	}
 	spin_unlock(&dasd_devmap_lock);
 	return count;
@@ -680,6 +687,13 @@
 {
 	return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);
 }
+
+void
+dasd_remove_sysfs_files(struct ccw_device *cdev)
+{
+	sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);
+}
+
 
 int
 dasd_devmap_init(void)
diff -Nru a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
--- a/drivers/s390/block/dasd_diag.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/s390/block/dasd_diag.c	Sat Apr  3 19:38:40 2004
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.33 $
+ * $Revision: 1.34 $
  */
 
 #include <linux/config.h>
@@ -173,7 +173,6 @@
 
 	if (!ip) {		/* no intparm: unsolicited interrupt */
 		MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
-		irq_exit();
 		return;
 	}
 	cqr = (struct dasd_ccw_req *)(addr_t) ip;
@@ -183,7 +182,6 @@
 			    " magic number of dasd_ccw_req 0x%08X doesn't"
 			    " match discipline 0x%08X",
 			    cqr->magic, *(int *) (&device->discipline->name));
-		irq_exit();
 		return;
 	}
 
diff -Nru a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
--- a/drivers/s390/block/dasd_eckd.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/s390/block/dasd_eckd.c	Sat Apr  3 19:38:40 2004
@@ -7,7 +7,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.51 $
+ * $Revision: 1.53 $
  */
 
 #include <linux/config.h>
@@ -1131,7 +1131,7 @@
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
 	cqr->device = device;
 	cqr->retries = 0;
-	cqr->expires = 10 * HZ;
+	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 
@@ -1174,7 +1174,7 @@
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
 	cqr->device = device;
 	cqr->retries = 0;
-	cqr->expires = 10 * HZ;
+	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 
@@ -1216,7 +1216,7 @@
 	cqr->cpaddr->cda = (__u32)(addr_t) cqr->data;
 	cqr->device = device;
 	cqr->retries = 0;
-	cqr->expires = 10 * HZ;
+	cqr->expires = 2 * HZ;
 	cqr->buildclk = get_clock();
 	cqr->status = DASD_CQR_FILLED;
 
@@ -1274,6 +1274,7 @@
 	stats = (struct dasd_rssd_perf_stats_t *) (prssdp + 1);
 	memset(stats, 0, sizeof (struct dasd_rssd_perf_stats_t));
 
+	ccw++;
 	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
 	ccw->count = sizeof (struct dasd_rssd_perf_stats_t);
 	ccw->cda = (__u32)(addr_t) stats;
diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
--- a/drivers/s390/block/dasd_genhd.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/s390/block/dasd_genhd.c	Sat Apr  3 19:38:54 2004
@@ -9,7 +9,7 @@
  *
  * gendisk related functions for the dasd driver.
  *
- * $Revision: 1.44 $
+ * $Revision: 1.46 $
  */
 
 #include <linux/config.h>
@@ -71,7 +71,7 @@
 
  	sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
 
-	if (device->ro_flag)
+	if (test_bit(DASD_FLAG_RO, &device->flags))
 		set_disk_ro(gdp, 1);
 	gdp->private_data = device;
 	gdp->queue = device->request_queue;
@@ -96,22 +96,33 @@
 /*
  * Trigger a partition detection.
  */
-void
+int
 dasd_scan_partitions(struct dasd_device * device)
 {
 	struct block_device *bdev;
 
 	/* Make the disk known. */
 	set_capacity(device->gdp, device->blocks << device->s2b_shift);
-	/* See fs/partition/check.c:register_disk,rescan_partitions */
 	bdev = bdget_disk(device->gdp, 0);
-	if (bdev) {
-		if (blkdev_get(bdev, FMODE_READ, 1) >= 0) {
-			/* Can't call rescan_partitions directly. Use ioctl. */
-			ioctl_by_bdev(bdev, BLKRRPART, 0);
-			blkdev_put(bdev);
-		}
-	}
+	if (!bdev || blkdev_get(bdev, FMODE_READ, 1) < 0)
+		return -ENODEV;
+	/*
+	 * See fs/partition/check.c:register_disk,rescan_partitions
+	 * Can't call rescan_partitions directly. Use ioctl.
+	 */
+	ioctl_by_bdev(bdev, BLKRRPART, 0);
+	/*
+	 * Since the matching blkdev_put call to the blkdev_get in
+	 * this function is not called before dasd_destroy_partitions
+	 * the offline open_count limit needs to be increased from
+	 * 0 to 1. This is done by setting device->bdev (see
+	 * dasd_generic_set_offline). As long as the partition
+	 * detection is running no offline should be allowed. That
+	 * is why the assignment to device->bdev is done AFTER
+	 * the BLKRRPART ioctl.
+	 */
+	device->bdev = bdev;
+	return 0;
 }
 
 /*
@@ -121,13 +132,32 @@
 void
 dasd_destroy_partitions(struct dasd_device * device)
 {
-	int p;
+	/* The two structs have 168/176 byte on 31/64 bit. */
+	struct blkpg_partition bpart;
+	struct blkpg_ioctl_arg barg;
+	struct block_device *bdev;
+
+	/*
+	 * Get the bdev pointer from the device structure and clear
+	 * device->bdev to lower the offline open_count limit again.
+	 */
+	bdev = device->bdev;
+	device->bdev = 0;
+
+	/*
+	 * See fs/partition/check.c:delete_partition
+	 * Can't call delete_partitions directly. Use ioctl.
+	 * The ioctl also does locking and invalidation.
+	 */
+	memset(&bpart, sizeof(struct blkpg_partition), 0);
+	memset(&barg, sizeof(struct blkpg_ioctl_arg), 0);
+	barg.data = &bpart;
+	for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
+		ioctl_by_bdev(bdev, BLKPG_DEL_PARTITION, (unsigned long) &barg);
 
-	for (p = device->gdp->minors - 1; p > 0; p--) {
-		invalidate_partition(device->gdp, p);
-		delete_partition(device->gdp, p);
-	}
 	invalidate_partition(device->gdp, 0);
+	/* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */
+	blkdev_put(bdev);
 	set_capacity(device->gdp, 0);
 }
 
diff -Nru a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
--- a/drivers/s390/block/dasd_int.h	Sat Apr  3 19:38:54 2004
+++ b/drivers/s390/block/dasd_int.h	Sat Apr  3 19:38:54 2004
@@ -6,7 +6,7 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
- * $Revision: 1.54 $
+ * $Revision: 1.56 $
  */
 
 #ifndef DASD_INT_H
@@ -268,14 +268,12 @@
 	struct gendisk *gdp;
 	request_queue_t *request_queue;
 	spinlock_t request_queue_lock;
+	struct block_device *bdev;
         unsigned int devindex;
 	unsigned long blocks;		/* size of volume in blocks */
 	unsigned int bp_block;		/* bytes per block */
 	unsigned int s2b_shift;		/* log2 (bp_block/512) */
-	int ro_flag;			/* read-only flag */
-	int use_diag_flag;		/* diag allowed flag */
-	int disconnect_error_flag;	/* return -EIO when disconnected */
-
+	unsigned long flags;		/* per device flags */
 
 	/* Device discipline stuff. */
 	struct dasd_discipline *discipline;
@@ -318,6 +316,11 @@
 #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
 #define DASD_STOPPED_DC_EIO  16        /* disconnected, return -EIO */
 
+/* per device flags */
+#define DASD_FLAG_RO		0	/* device is read-only */
+#define DASD_FLAG_USE_DIAG	1	/* use diag disciplnie */
+#define DASD_FLAG_DSC_ERROR	2	/* return -EIO when disconnected */
+#define DASD_FLAG_OFFLINE	3	/* device is in offline processing */
 
 void dasd_put_device_wake(struct dasd_device *);
 
@@ -485,6 +488,8 @@
 void dasd_delete_device(struct dasd_device *);
 
 int dasd_add_sysfs_files(struct ccw_device *);
+void dasd_remove_sysfs_files(struct ccw_device *);
+
 struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
 struct dasd_device *dasd_device_from_devindex(int);
 
@@ -496,7 +501,7 @@
 void dasd_gendisk_exit(void);
 int dasd_gendisk_alloc(struct dasd_device *);
 void dasd_gendisk_free(struct dasd_device *);
-void dasd_scan_partitions(struct dasd_device *);
+int dasd_scan_partitions(struct dasd_device *);
 void dasd_destroy_partitions(struct dasd_device *);
 
 /* externals in dasd_ioctl.c */
diff -Nru a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
--- a/drivers/s390/block/dasd_ioctl.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/s390/block/dasd_ioctl.c	Sat Apr  3 19:38:44 2004
@@ -303,7 +303,7 @@
 
 	if (device == NULL)
 		return -ENODEV;
-	if (device->ro_flag)
+	if (test_bit(DASD_FLAG_RO, &device->flags))
 		return -EROFS;
 	if (copy_from_user(&fdata, (void *) args,
 			   sizeof (struct format_data_t)))
@@ -415,8 +415,8 @@
 	    (dasd_check_blocksize(device->bp_block)))
 		dasd_info->format = DASD_FORMAT_NONE;
 	
-	dasd_info->features |= device->ro_flag ? DASD_FEATURE_READONLY
-					       : DASD_FEATURE_DEFAULT;
+	dasd_info->features |= test_bit(DASD_FLAG_RO, &device->flags) ?
+		DASD_FEATURE_READONLY : DASD_FEATURE_DEFAULT;
 
 	if (device->discipline)
 		memcpy(dasd_info->type, device->discipline->name, 4);
@@ -472,7 +472,10 @@
 	if (device == NULL)
 		return -ENODEV;
 	set_disk_ro(bdev->bd_disk, intval);
-	device->ro_flag = intval;
+	if (intval)
+		set_bit(DASD_FLAG_RO, &device->flags);
+	else
+		clear_bit(DASD_FLAG_RO, &device->flags);
 	return 0;
 }
 
diff -Nru a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
--- a/drivers/s390/block/dasd_proc.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/s390/block/dasd_proc.c	Sat Apr  3 19:38:41 2004
@@ -9,7 +9,7 @@
  *
  * /proc interface for the dasd driver.
  *
- * $Revision: 1.26 $
+ * $Revision: 1.27 $
  */
 
 #include <linux/config.h>
@@ -77,7 +77,7 @@
 	else
 		seq_printf(m, " is ????????");
 	/* Print devices features. */
-	substr = device->ro_flag ? "(ro)" : " ";
+	substr = test_bit(DASD_FLAG_RO, &device->flags) ? "(ro)" : " ";
 	seq_printf(m, "%4s: ", substr);
 	/* Print device status information. */
 	switch ((device != NULL) ? device->state : -1) {
diff -Nru a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
--- a/drivers/s390/char/Makefile	Sat Apr  3 19:38:43 2004
+++ b/drivers/s390/char/Makefile	Sat Apr  3 19:38:43 2004
@@ -18,6 +18,6 @@
 
 tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o
 tape-$(CONFIG_PROC_FS) += tape_proc.o
-tape-objs := tape_core.o tape_std.o tape_char.o tape_class.o $(tape-y)
-obj-$(CONFIG_S390_TAPE) += tape.o
+tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y)
+obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o
 obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o
diff -Nru a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
--- a/drivers/s390/char/sclp.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/s390/char/sclp.c	Sat Apr  3 19:38:44 2004
@@ -335,8 +335,8 @@
 	unsigned long psw_mask;
 	unsigned long cr0, cr0_sync;
 
-	/* Need to irq_enter() to prevent BH from executing. */
-	irq_enter();
+	/* Prevent BH from executing. */
+	local_bh_disable();
 	/*
 	 * save cr0
 	 * enable service signal external interruption (cr0.22)
@@ -365,7 +365,7 @@
 
 	/* restore cr0 */
 	__ctl_load(cr0, 0, 0);
-	irq_exit();
+	__local_bh_enable();
 }
 
 /*
diff -Nru a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
--- a/drivers/s390/char/tape.h	Sat Apr  3 19:38:45 2004
+++ b/drivers/s390/char/tape.h	Sat Apr  3 19:38:45 2004
@@ -198,9 +198,10 @@
 	/* entry in tape_device_list */
 	struct list_head		node;
 
+	int				cdev_id;
 	struct ccw_device *		cdev;
-	struct cdev *			nt;
-	struct cdev *			rt;
+	struct tape_class_device *	nt;
+	struct tape_class_device *	rt;
 
 	/* Device discipline information. */
 	struct tape_discipline *	discipline;
@@ -263,8 +264,8 @@
 extern int tape_mtop(struct tape_device *, int, int);
 extern void tape_state_set(struct tape_device *, enum tape_state);
 
-extern int tape_enable_device(struct tape_device *, struct tape_discipline *);
-extern void tape_disable_device(struct tape_device *device);
+extern int tape_generic_online(struct tape_device *, struct tape_discipline *);
+extern int tape_generic_offline(struct tape_device *device);
 
 /* Externals from tape_devmap.c */
 extern int tape_generic_probe(struct ccw_device *);
diff -Nru a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
--- a/drivers/s390/char/tape_34xx.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/s390/char/tape_34xx.c	Sat Apr  3 19:38:42 2004
@@ -202,8 +202,7 @@
 		tape_34xx_delete_sbid_from(device, 0);
 		tape_34xx_schedule_work(device, TO_MSEN);
 	} else {
-		DBF_EVENT(3, "unsol.irq! dev end: %s\n",
-				device->cdev->dev.bus_id);
+		DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
 		PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
 		tape_dump_sense(device, NULL, irb);
 	}
@@ -1314,17 +1313,18 @@
 };
 
 static int
-tape_34xx_enable(struct ccw_device *cdev)
+tape_34xx_online(struct ccw_device *cdev)
 {
-	return tape_enable_device(cdev->dev.driver_data,
-				  &tape_discipline_34xx);
+	return tape_generic_online(
+		cdev->dev.driver_data,
+		&tape_discipline_34xx
+	);
 }
 
 static int
-tape_34xx_disable(struct ccw_device *cdev)
+tape_34xx_offline(struct ccw_device *cdev)
 {
-	tape_disable_device(cdev->dev.driver_data);
-	return 0;
+	return tape_generic_offline(cdev->dev.driver_data);
 }
 
 static struct ccw_driver tape_34xx_driver = {
@@ -1333,8 +1333,8 @@
 	.ids = tape_34xx_ids,
 	.probe = tape_generic_probe,
 	.remove = tape_generic_remove,
-	.set_online = tape_34xx_enable,
-	.set_offline = tape_34xx_disable,
+	.set_online = tape_34xx_online,
+	.set_offline = tape_34xx_offline,
 };
 
 static int
@@ -1342,7 +1342,7 @@
 {
 	int rc;
 
-	DBF_EVENT(3, "34xx init: $Revision: 1.18 $\n");
+	DBF_EVENT(3, "34xx init: $Revision: 1.19 $\n");
 	/* Register driver for 3480/3490 tapes. */
 	rc = ccw_driver_register(&tape_34xx_driver);
 	if (rc)
@@ -1361,7 +1361,7 @@
 MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);
 MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
 MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape "
-		   "device driver ($Revision: 1.18 $)");
+		   "device driver ($Revision: 1.19 $)");
 MODULE_LICENSE("GPL");
 
 module_init(tape_34xx_init);
diff -Nru a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
--- a/drivers/s390/char/tape_block.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/s390/char/tape_block.c	Sat Apr  3 19:38:54 2004
@@ -274,12 +274,19 @@
 	flush_scheduled_work();
 	device->blk_data.requeue_task.data = tape_put_device(device);
 
+	if (!device->blk_data.disk) {
+		PRINT_ERR("(%s): No gendisk to clean up!\n",
+			device->cdev->dev.bus_id);
+		goto cleanup_queue;
+	}
+
 	del_gendisk(device->blk_data.disk);
 	device->blk_data.disk->private_data =
 		tape_put_device(device->blk_data.disk->private_data);
 	put_disk(device->blk_data.disk);
 
 	device->blk_data.disk = NULL;
+cleanup_queue:
 	device->blk_data.request_queue->queuedata = tape_put_device(device);
 
 	blk_cleanup_queue(device->blk_data.request_queue);
diff -Nru a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
--- a/drivers/s390/char/tape_char.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/s390/char/tape_char.c	Sat Apr  3 19:38:54 2004
@@ -48,38 +48,29 @@
 
 static int tapechar_major = TAPECHAR_MAJOR;
 
-struct cdev *
-tapechar_register_tape_dev(struct tape_device *device, char *name, int i)
-{
-	struct cdev *	cdev;
-	char		devname[11];
-
-	sprintf(devname, "%s%i", name, i / 2);
-	cdev = register_tape_dev(
-		&device->cdev->dev,
-		MKDEV(tapechar_major, i),
-		&tape_fops,
-		devname
-	);
-
-	return ((IS_ERR(cdev)) ? NULL : cdev);
-}
-
 /*
  * This function is called for every new tapedevice
  */
 int
 tapechar_setup_device(struct tape_device * device)
 {
-	device->nt = tapechar_register_tape_dev(
-			device,
-			"ntibm",
-			device->first_minor
+	char	device_name[20];
+
+	sprintf(device_name, "ntibm%i", device->first_minor / 2);
+	device->nt = register_tape_dev(
+		&device->cdev->dev,
+		MKDEV(tapechar_major, device->first_minor),
+		&tape_fops,
+		device_name,
+		"non-rewinding"
 	);
-	device->rt = tapechar_register_tape_dev(
-			device,
-			"rtibm",
-			device->first_minor + 1
+	device_name[0] = 'r';
+	device->rt = register_tape_dev(
+		&device->cdev->dev,
+		MKDEV(tapechar_major, device->first_minor + 1),
+		&tape_fops,
+		device_name,
+		"rewinding"
 	);
 
 	return 0;
@@ -500,9 +491,6 @@
 	tapechar_major = MAJOR(dev);
 	PRINT_INFO("tape gets major %d for character devices\n", MAJOR(dev));
 
-#ifdef TAPE390_INTERNAL_CLASS
-	tape_setup_class();
-#endif
 	return 0;
 }
 
@@ -512,9 +500,6 @@
 void
 tapechar_exit(void)
 {
-#ifdef TAPE390_INTERNAL_CLASS
-	tape_cleanup_class();
-#endif
 	PRINT_INFO("tape releases major %d for character devices\n",
 		tapechar_major);
 	unregister_chrdev_region(MKDEV(tapechar_major, 0), 256);
diff -Nru a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c
--- a/drivers/s390/char/tape_class.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/s390/char/tape_class.c	Sat Apr  3 19:38:55 2004
@@ -1,4 +1,7 @@
 /*
+ * (C) Copyright IBM Corp. 2004
+ * tape_class.c ($Revision: 1.6 $)
+ *
  * Tape class device support
  *
  * Author: Stefan Bader <shbader@de.ibm.com>
@@ -6,11 +9,12 @@
  */
 #include "tape_class.h"
 
-#ifndef TAPE390_INTERNAL_CLASS
 MODULE_AUTHOR("Stefan Bader <shbader@de.ibm.com>");
-MODULE_DESCRIPTION("Tape class");
+MODULE_DESCRIPTION(
+	"(C) Copyright IBM Corp. 2004   All Rights Reserved.\n"
+	"tape_class.c ($Revision: 1.6 $)"
+);
 MODULE_LICENSE("GPL");
-#endif
 
 struct class_simple *tape_class;
 
@@ -29,72 +33,94 @@
  * devname
  *	The pointer to the name of the character device.
  */
-struct cdev *register_tape_dev(
+struct tape_class_device *register_tape_dev(
 	struct device *		device,
 	dev_t			dev,
 	struct file_operations *fops,
-	char *			devname
-) {
-	struct cdev *	cdev;
+	char *			device_name,
+	char *			mode_name)
+{
+	struct tape_class_device *	tcd;
 	int		rc;
 	char *		s;
 
-	cdev = cdev_alloc();
-	if (!cdev)
+	tcd = kmalloc(sizeof(struct tape_class_device), GFP_KERNEL);
+	if (!tcd)
 		return ERR_PTR(-ENOMEM);
 
-	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, '/'))
+	memset(tcd, 0, sizeof(struct tape_class_device));
+	strncpy(tcd->device_name, device_name, TAPECLASS_NAME_LEN);
+	for (s = strchr(tcd->device_name, '/'); s; s = strchr(s, '/'))
+		*s = '!';
+	strncpy(tcd->mode_name, mode_name, TAPECLASS_NAME_LEN);
+	for (s = strchr(tcd->mode_name, '/'); s; s = strchr(s, '/'))
 		*s = '!';
 
-	rc = cdev_add(cdev, cdev->dev, 1);
-	if (rc) {
-		kobject_put(&cdev->kobj);
-		return ERR_PTR(rc);
+	tcd->char_device = cdev_alloc();
+	if (!tcd->char_device) {
+		rc = -ENOMEM;
+		goto fail_with_tcd;
 	}
-	class_simple_device_add(tape_class, cdev->dev, device, "%s", devname);
 
-	return cdev;
+	tcd->char_device->owner = fops->owner;
+	tcd->char_device->ops   = fops;
+	tcd->char_device->dev   = dev;
+
+	rc = cdev_add(tcd->char_device, tcd->char_device->dev, 1);
+	if (rc)
+		goto fail_with_cdev;
+
+	tcd->class_device = class_simple_device_add(
+				tape_class,
+				tcd->char_device->dev,
+				device,
+				"%s", tcd->device_name
+			);
+	sysfs_create_link(
+		&device->kobj,
+		&tcd->class_device->kobj,
+		tcd->mode_name
+	);
+
+	return tcd;
+
+fail_with_cdev:
+	cdev_del(&tcd->char_device);
+
+fail_with_tcd:
+	kfree(tcd);
+
+	return ERR_PTR(rc);
 }
 EXPORT_SYMBOL(register_tape_dev);
 
-void unregister_tape_dev(struct cdev *cdev)
+void unregister_tape_dev(struct tape_class_device *tcd)
 {
-	if (cdev != NULL) {
-		class_simple_device_remove(cdev->dev);
-		cdev_del(cdev);
+	if (tcd != NULL && !IS_ERR(tcd)) {
+		sysfs_remove_link(
+			&tcd->class_device->dev->kobj,
+			tcd->mode_name
+		);
+		class_simple_device_remove(tcd->char_device->dev);
+		cdev_del(tcd->char_device);
+		kfree(tcd);
 	}
 }
 EXPORT_SYMBOL(unregister_tape_dev);
 
 
-#ifndef TAPE390_INTERNAL_CLASS
 static int __init tape_init(void)
-#else
-int tape_setup_class(void)
-#endif
 {
 	tape_class = class_simple_create(THIS_MODULE, "tape390");
+
 	return 0;
 }
 
-#ifndef TAPE390_INTERNAL_CLASS
 static void __exit tape_exit(void)
-#else
-void tape_cleanup_class(void)
-#endif
 {
 	class_simple_destroy(tape_class);
 	tape_class = NULL;
 }
 
-#ifndef TAPE390_INTERNAL_CLASS
 postcore_initcall(tape_init);
 module_exit(tape_exit);
-#else
-EXPORT_SYMBOL(tape_setup_class);
-EXPORT_SYMBOL(tape_cleanup_class);
-#endif
diff -Nru a/drivers/s390/char/tape_class.h b/drivers/s390/char/tape_class.h
--- a/drivers/s390/char/tape_class.h	Sat Apr  3 19:38:42 2004
+++ b/drivers/s390/char/tape_class.h	Sat Apr  3 19:38:42 2004
@@ -1,4 +1,7 @@
 /*
+ * (C) Copyright IBM Corp. 2004   All Rights Reserved.
+ * tape_class.h ($Revision: 1.4 $)
+ *
  * Tape class device support
  *
  * Author: Stefan Bader <shbader@de.ibm.com>
@@ -7,11 +10,8 @@
 #ifndef __TAPE_CLASS_H__
 #define __TAPE_CLASS_H__
 
-#if 0
 #include <linux/init.h>
 #include <linux/module.h>
-#endif
-
 #include <linux/fs.h>
 #include <linux/major.h>
 #include <linux/kobject.h>
@@ -21,34 +21,41 @@
 #include <linux/device.h>
 #include <linux/kdev_t.h>
 
-#define TAPE390_INTERNAL_CLASS
+#define TAPECLASS_NAME_LEN	32
+
+struct tape_class_device {
+	struct cdev *		char_device;
+	struct class_device *	class_device;
+	char			device_name[TAPECLASS_NAME_LEN];
+	char			mode_name[TAPECLASS_NAME_LEN];
+};
 
 /*
- * Register a tape device and return a pointer to the cdev structure.
+ * Register a tape device and return a pointer to the tape class device
+ * created by the call.
  *
  * device
  *	The pointer to the struct device of the physical (base) device.
- * drivername
- *	The pointer to the drivers name for it's character devices.
  * dev
  *	The intended major/minor number. The major number may be 0 to
  *	get a dynamic major number.
  * fops
  *	The pointer to the drivers file operations for the tape device.
- * devname
- *	The pointer to the name of the character device.
+ * device_name
+ *	Pointer to the logical device name (will also be used as kobject name
+ *	of the cdev). This can also be called the name of the tape class
+ *	device.
+ * mode_name
+ *	Points to the name of the tape mode. This creates a link with that
+ *	name from the physical device to the logical device (class).
  */
-struct cdev *register_tape_dev(
+struct tape_class_device *register_tape_dev(
 	struct device *		device,
 	dev_t			dev,
 	struct file_operations *fops,
-	char *			devname
+	char *			device_name,
+	char *			node_name
 );
-void unregister_tape_dev(struct cdev *cdev);
-
-#ifdef TAPE390_INTERNAL_CLASS
-int tape_setup_class(void);
-void tape_cleanup_class(void);
-#endif
+void unregister_tape_dev(struct tape_class_device *tcd);
 
 #endif /* __TAPE_CLASS_H__ */
diff -Nru a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
--- a/drivers/s390/char/tape_core.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/s390/char/tape_core.c	Sat Apr  3 19:38:42 2004
@@ -69,6 +69,34 @@
 	[TO_UNASSIGN] = "UAS"
 };
 
+static inline int
+busid_to_int(char *bus_id)
+{
+	int	dec;
+	int	d;
+	char *	s;
+
+	for(s = bus_id, d = 0; *s != '\0' && *s != '.'; s++)
+		d = (d * 10) + (*s - '0');
+	dec = d;
+	for(s++, d = 0; *s != '\0' && *s != '.'; s++)
+		d = (d * 10) + (*s - '0');
+	dec = (dec << 8) + d;
+
+	for(s++; *s != '\0'; s++) {
+		if (*s >= '0' && *s <= '9') {
+			d = *s - '0';
+		} else if (*s >= 'a' && *s <= 'f') {
+			d = *s - 'a' + 10;
+		} else {
+			d = *s - 'A' + 10;
+		}
+		dec = (dec << 4) + d;
+	}
+
+	return dec;
+}
+
 /*
  * Some channel attached tape specific attributes.
  *
@@ -296,10 +324,15 @@
 }
 
 /*
- * Enable tape device
+ * Set a device online.
+ *
+ * This function is called by the common I/O layer to move a device from the
+ * detected but offline into the online state.
+ * If we return an error (RC < 0) the device remains in the offline state. This
+ * can happen if the device is assigned somewhere else, for example.
  */
 int
-tape_enable_device(struct tape_device *device,
+tape_generic_online(struct tape_device *device,
 		   struct tape_discipline *discipline)
 {
 	int rc;
@@ -328,6 +361,9 @@
 		goto out_char;
 
 	tape_state_set(device, TS_UNUSED);
+
+	DBF_LH(3, "(%08x): Drive set online\n", device->cdev_id);
+
 	return 0;
 
 out_char:
@@ -342,37 +378,49 @@
 }
 
 /*
- * Disable tape device. Check if there is a running request and
- * terminate it. Post all queued requests with -EIO.
+ * Set device offline.
+ *
+ * Called by the common I/O layer if the drive should set offline on user
+ * request. We may prevent this by returning an error.
+ * Manual offline is only allowed while the drive is not in use.
  */
-void
-tape_disable_device(struct tape_device *device)
+int
+tape_generic_offline(struct tape_device *device)
 {
-	struct list_head *l, *n;
-	struct tape_request *request;
+	if (!device) {
+		PRINT_ERR("tape_generic_offline: no such device\n");
+		return -ENODEV;
+	}
+
+	DBF_LH(3, "(%08x): tape_generic_offline(%p)\n",
+		device->cdev_id, device);
 
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
-	/* Post remaining requests with -EIO */
-	list_for_each_safe(l, n, &device->req_queue) {
-		request = list_entry(l, struct tape_request, list);
-		if (request->status == TAPE_REQUEST_IN_IO)
-			__tape_halt_io(device, request);
-		list_del(&request->list);
-		/* Decrease ref_count for removed request. */
-		request->device = tape_put_device(device);
-		request->rc = -EIO;
-		if (request->callback != NULL)
-			request->callback(request, request->callback_data);
+	switch (device->tape_state) {
+		case TS_INIT:
+		case TS_NOT_OPER:
+			break;
+		case TS_UNUSED:
+			tapeblock_cleanup_device(device);
+			tapechar_cleanup_device(device);
+			device->discipline->cleanup_device(device);
+			tape_remove_minor(device);
+		default:
+			DBF_EVENT(3, "(%08x): Set offline failed "
+				"- drive in use.\n",
+				device->cdev_id);
+			PRINT_WARN("(%s): Set offline failed "
+				"- drive in use.\n",
+				device->cdev->dev.bus_id);
+			spin_unlock_irq(get_ccwdev_lock(device->cdev));
+			return -EBUSY;
 	}
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
 
-	tapeblock_cleanup_device(device);
-	tapechar_cleanup_device(device);
-	device->discipline->cleanup_device(device);
-	tape_remove_minor(device);
-
 	tape_med_state_set(device, MS_UNKNOWN);
-	device->tape_state = TS_INIT;
+
+	DBF_LH(3, "(%08x): Drive set offline.\n", device->cdev_id);
+	return 0;
 }
 
 /*
@@ -479,14 +527,14 @@
 tape_generic_probe(struct ccw_device *cdev)
 {
 	struct tape_device *device;
-	char *bus_id = cdev->dev.bus_id;
 
 	device = tape_alloc_device();
 	if (IS_ERR(device))
 		return -ENODEV;
-	PRINT_INFO("tape device %s found\n", bus_id);
+	PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);
 	cdev->dev.driver_data = device;
 	device->cdev = cdev;
+	device->cdev_id = busid_to_int(cdev->dev.bus_id);
 	cdev->handler = __tape_do_irq;
 
 	ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
@@ -497,15 +545,58 @@
 
 /*
  * Driverfs tape remove function.
+ *
+ * This function is called whenever the common I/O layer detects the device
+ * gone. This can happen at any time and we cannot refuse.
  */
 void
 tape_generic_remove(struct ccw_device *cdev)
 {
-	ccw_device_set_offline(cdev);
+	struct tape_device *	device;
+	struct tape_request *	request;
+	struct list_head *	l, *n;
+
+	device = cdev->dev.driver_data;
+	DBF_LH(3, "(%08x): tape_generic_remove(%p)\n", device->cdev_id, cdev);
+
+	/*
+	 * No more requests may be processed. So just post them as i/o errors.
+	 */
+	spin_lock_irq(get_ccwdev_lock(device->cdev));
+	list_for_each_safe(l, n, &device->req_queue) {
+		request = list_entry(l, struct tape_request, list);
+		if (request->status == TAPE_REQUEST_IN_IO)
+			request->status = TAPE_REQUEST_DONE;
+		list_del(&request->list);
+
+		/* Decrease ref_count for removed request. */
+		request->device = tape_put_device(device);
+		request->rc = -EIO;
+		if (request->callback != NULL)
+			request->callback(request, request->callback_data);
+	}
+
+	if (device->tape_state != TS_UNUSED && device->tape_state != TS_INIT) {
+		DBF_EVENT(3, "(%08x): Drive in use vanished!\n",
+			device->cdev_id);
+		PRINT_WARN("(%s): Drive in use vanished - expect trouble!\n",
+			device->cdev->dev.bus_id);
+		PRINT_WARN("State was %i\n", device->tape_state);
+		device->tape_state = TS_NOT_OPER;
+		tapeblock_cleanup_device(device);
+		tapechar_cleanup_device(device);
+		device->discipline->cleanup_device(device);
+		tape_remove_minor(device);
+	}
+	device->tape_state = TS_NOT_OPER;
+	tape_med_state_set(device, MS_UNKNOWN);
+	spin_unlock_irq(get_ccwdev_lock(device->cdev));
+
 	if (cdev->dev.driver_data != NULL) {
 		sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group);
 		cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data);
 	}
+
 }
 
 /*
@@ -665,7 +756,7 @@
 		op = "---";
 	DBF_EVENT(3, "DSTAT : %02x   CSTAT: %02x\n",
 		  irb->scsw.dstat,irb->scsw.cstat);
-	DBF_EVENT(3, "DEVICE: %s OP\t: %s\n", device->cdev->dev.bus_id,op);
+	DBF_EVENT(3, "DEVICE: %08x OP\t: %s\n", device->cdev_id, op);
 	sptr = (unsigned int *) irb->ecw;
 	DBF_EVENT(3, "%08x %08x\n", sptr[0], sptr[1]);
 	DBF_EVENT(3, "%08x %08x\n", sptr[2], sptr[3]);
@@ -815,7 +906,7 @@
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	rc = __tape_halt_io(device, request);
 	if (rc == 0) {
-		DBF_EVENT(3, "IO stopped on %s\n", device->cdev->dev.bus_id);
+		DBF_EVENT(3, "IO stopped on %08x\n", device->cdev_id);
 		rc = -ERESTARTSYS;
 	}
 	spin_unlock_irq(get_ccwdev_lock(device->cdev));
@@ -823,6 +914,24 @@
 }
 
 /*
+ * Handle requests that return an i/o error in the irb.
+ */
+static inline void
+tape_handle_killed_request(
+	struct tape_device *device,
+	struct tape_request *request)
+{
+	if(request != NULL) {
+		/* Set ending status. FIXME: Should the request be retried? */
+		request->rc = -EIO;
+		request->status = TAPE_REQUEST_DONE;
+		__tape_remove_request(device, request);
+	} else {
+		__tape_do_io_list(device);
+	}
+}
+
+/*
  * Tape interrupt routine, called from the ccw_device layer
  */
 static void
@@ -835,7 +944,7 @@
 
 	device = (struct tape_device *) cdev->dev.driver_data;
 	if (device == NULL) {
-		PRINT_ERR("could not get device structure for bus_id %s "
+		PRINT_ERR("could not get device structure for %s "
 			  "in interrupt\n", cdev->dev.bus_id);
 		return;
 	}
@@ -843,6 +952,23 @@
 
 	DBF_LH(6, "__tape_do_irq(device=%p, request=%p)\n", device, request);
 
+	/* On special conditions irb is an error pointer */
+	if (IS_ERR(irb)) {
+		switch (PTR_ERR(irb)) {
+			case -ETIMEDOUT:
+				PRINT_WARN("(%s): Request timed out\n",
+					cdev->dev.bus_id);
+			case -EIO:
+				tape_handle_killed_request(device, request);
+				break;
+			default:
+				PRINT_ERR("(%s): Unexpected i/o error %li\n",
+					cdev->dev.bus_id,
+					PTR_ERR(irb));
+		}
+		return;
+	}
+
 	/* May be an unsolicited irq */
 	if(request != NULL)
 		request->rescnt = irb->scsw.count;
@@ -1023,7 +1149,7 @@
 #ifdef DBF_LIKE_HELL
 	debug_set_level(tape_dbf_area, 6);
 #endif
-	DBF_EVENT(3, "tape init: ($Revision: 1.44 $)\n");
+	DBF_EVENT(3, "tape init: ($Revision: 1.48 $)\n");
 	tape_proc_init();
 	tapechar_init ();
 	tapeblock_init ();
@@ -1048,7 +1174,7 @@
 MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and "
 	      "Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)");
 MODULE_DESCRIPTION("Linux on zSeries channel attached "
-		   "tape device driver ($Revision: 1.44 $)");
+		   "tape device driver ($Revision: 1.48 $)");
 MODULE_LICENSE("GPL");
 
 module_init(tape_init);
@@ -1056,9 +1182,9 @@
 
 EXPORT_SYMBOL(tape_dbf_area);
 EXPORT_SYMBOL(tape_generic_remove);
-EXPORT_SYMBOL(tape_disable_device);
 EXPORT_SYMBOL(tape_generic_probe);
-EXPORT_SYMBOL(tape_enable_device);
+EXPORT_SYMBOL(tape_generic_online);
+EXPORT_SYMBOL(tape_generic_offline);
 EXPORT_SYMBOL(tape_put_device);
 EXPORT_SYMBOL(tape_get_device_reference);
 EXPORT_SYMBOL(tape_state_verbose);
diff -Nru a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
--- a/drivers/s390/char/tape_std.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/s390/char/tape_std.c	Sat Apr  3 19:38:40 2004
@@ -42,8 +42,8 @@
 
 	spin_lock_irq(get_ccwdev_lock(device->cdev));
 	if (request->callback != NULL) {
-		DBF_EVENT(3, "%s: Assignment timeout. Device busy.\n",
-			device->cdev->dev.bus_id);
+		DBF_EVENT(3, "%08x: Assignment timeout. Device busy.\n",
+			device->cdev_id);
 		PRINT_ERR("%s: Assignment timeout. Device busy.\n",
 			device->cdev->dev.bus_id);
 		ccw_device_clear(device->cdev, (long) request);
@@ -84,10 +84,10 @@
 	if (rc != 0) {
 		PRINT_WARN("%s: assign failed - device might be busy\n",
 			device->cdev->dev.bus_id);
-		DBF_EVENT(3, "%s: assign failed - device might be busy\n",
-			device->cdev->dev.bus_id);
+		DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
+			device->cdev_id);
 	} else {
-		DBF_EVENT(3, "%s: Tape assigned\n", device->cdev->dev.bus_id);
+		DBF_EVENT(3, "%08x: Tape assigned\n", device->cdev_id);
 	}
 	tape_free_request(request);
 	return rc;
@@ -102,6 +102,14 @@
 	int                  rc;
 	struct tape_request *request;
 
+	if (device->tape_state == TS_NOT_OPER) {
+		DBF_EVENT(3, "(%08x): Can't unassign device\n",
+			device->cdev_id);
+		PRINT_WARN("(%s): Can't unassign device - device gone\n",
+			device->cdev->dev.bus_id);
+		return -EIO;
+	}
+
 	request = tape_alloc_request(2, 11);
 	if (IS_ERR(request))
 		return PTR_ERR(request);
@@ -111,10 +119,10 @@
 	tape_ccw_end(request->cpaddr + 1, NOP, 0, NULL);
 
 	if ((rc = tape_do_io(device, request)) != 0) {
-		DBF_EVENT(3, "%s: Unassign failed\n", device->cdev->dev.bus_id);
+		DBF_EVENT(3, "%08x: Unassign failed\n", device->cdev_id);
 		PRINT_WARN("%s: Unassign failed\n", device->cdev->dev.bus_id);
 	} else {
-		DBF_EVENT(3, "%s: Tape unassigned\n", device->cdev->dev.bus_id);
+		DBF_EVENT(3, "%08x: Tape unassigned\n", device->cdev_id);
 	}
 	tape_free_request(request);
 	return rc;
diff -Nru a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
--- a/drivers/s390/cio/blacklist.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/s390/cio/blacklist.c	Sat Apr  3 19:38:42 2004
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/blacklist.c
  *   S/390 common I/O routines -- blacklisting of specific devices
- *   $Revision: 1.29 $
+ *   $Revision: 1.31 $
  *
  *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
  *			      IBM Corporation
@@ -72,7 +72,10 @@
 blacklist_busid(char **str, int *id0, int *id1, int *devno)
 {
 	int val, old_style;
- 
+	char *sav;
+
+	sav = *str;
+
 	/* check for leading '0x' */
 	old_style = 0;
 	if ((*str)[0] == '0' && (*str)[1] == 'x') {
@@ -80,44 +83,54 @@
 		old_style = 1;
 	}
 	if (!isxdigit((*str)[0]))	/* We require at least one hex digit */
-		return -EINVAL;
+		goto confused;
 	val = simple_strtoul(*str, str, 16);
 	if (old_style || (*str)[0] != '.') {
 		*id0 = *id1 = 0;
 		if (val < 0 || val > 0xffff)
-			return -EINVAL;
+			goto confused;
 		*devno = val;
+		if ((*str)[0] != ',' && (*str)[0] != '-' &&
+		    (*str)[0] != '\n' && (*str)[0] != '\0')
+			goto confused;
 		return 0;
 	}
 	/* New style x.y.z busid */
 	if (val < 0 || val > 0xff)
-		return -EINVAL;
+		goto confused;
 	*id0 = val;
 	(*str)++;
 	if (!isxdigit((*str)[0]))	/* We require at least one hex digit */
-		return -EINVAL;
+		goto confused;
 	val = simple_strtoul(*str, str, 16);
 	if (val < 0 || val > 0xff || (*str)++[0] != '.')
-		return -EINVAL;
+		goto confused;
 	*id1 = val;
 	if (!isxdigit((*str)[0]))	/* We require at least one hex digit */
-		return -EINVAL;
+		goto confused;
 	val = simple_strtoul(*str, str, 16);
 	if (val < 0 || val > 0xffff)
-		return -EINVAL;
+		goto confused;
 	*devno = val;
+	if ((*str)[0] != ',' && (*str)[0] != '-' &&
+	    (*str)[0] != '\n' && (*str)[0] != '\0')
+		goto confused;
 	return 0;
+confused:
+	strsep(str, ",\n");
+	printk(KERN_WARNING "Invalid cio_ignore parameter '%s'\n", sav);
+	return 1;
 }
 
 static inline int
 blacklist_parse_parameters (char *str, range_action action)
 {
 	unsigned int from, to, from_id0, to_id0, from_id1, to_id1;
-	char *sav;
 
-	sav = str;
 	while (*str != 0 && *str != '\n') {
 		range_action ra = action;
+		while(*str == ',')
+			str++;
 		if (*str == '!') {
 			ra = !action;
 			++str;
@@ -138,32 +151,37 @@
 			rc = blacklist_busid(&str, &from_id0,
 					     &from_id1, &from);
 			if (rc)
-				goto out_err;
+				continue;
 			to = from;
 			to_id0 = from_id0;
 			to_id1 = from_id1;
 			if (*str == '-') {
 				str++;
-				rc = blacklist_busid(&str, &to_id0, &to_id1,
-						     &to);
+				rc = blacklist_busid(&str, &to_id0,
+						     &to_id1, &to);
 				if (rc)
-					goto out_err;
+					continue;
+			}
+			if (*str == '-') {
+				printk(KERN_WARNING "invalid cio_ignore "
+					"parameter '%s'\n",
+					strsep(&str, ",\n"));
+				continue;
+			}
+			if ((from_id0 != to_id0) || (from_id1 != to_id1)) {
+				printk(KERN_WARNING "invalid cio_ignore range "
+					"%x.%x.%04x-%x.%x.%04x\n",
+					from_id0, from_id1, from,
+					to_id0, to_id1, to);
+				continue;
 			}
-			if ((from_id0 != to_id0) || (from_id1 != to_id1))
-				goto out_err;
 		}
 		/* FIXME: ignoring id0 and id1 here. */
 		pr_debug("blacklist_setup: adding range "
 			 "from 0.0.%04x to 0.0.%04x\n", from, to);
 		blacklist_range (ra, from, to);
-
-		if (*str == ',')
-			str++;
 	}
 	return 1;
-out_err:
-	printk(KERN_WARNING "blacklist_setup: error parsing \"%s\"\n", sav);
-	return 0;
 }
 
 /* Parsing the commandline for blacklist parameters, e.g. to blacklist
diff -Nru a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
--- a/drivers/s390/cio/ccwgroup.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/s390/cio/ccwgroup.c	Sat Apr  3 19:38:44 2004
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/ccwgroup.c
  *  bus driver for ccwgroup
- *   $Revision: 1.24 $
+ *   $Revision: 1.25 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *                       IBM Corporation
@@ -102,8 +102,10 @@
 
 	gdev = to_ccwgroupdev(dev);
 
-	for (i = 0; i < gdev->count; i++)
+	for (i = 0; i < gdev->count; i++) {
+		gdev->cdev[i]->dev.driver_data = NULL;
 		put_device(&gdev->cdev[i]->dev);
+	}
 	kfree(gdev);
 }
 
@@ -155,6 +157,7 @@
 	struct ccwgroup_device *gdev;
 	int i;
 	int rc;
+	int del_drvdata;
 
 	if (argc > 256) /* disallow dumb users */
 		return -EINVAL;
@@ -166,6 +169,7 @@
 	memset(gdev, 0, sizeof(*gdev) + argc*sizeof(gdev->cdev[0]));
 	atomic_set(&gdev->onoff, 0);
 
+	del_drvdata = 0;
 	for (i = 0; i < argc; i++) {
 		gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
 
@@ -177,7 +181,15 @@
 			rc = -EINVAL;
 			goto error;
 		}
+		/* Don't allow a device to belong to more than one group. */
+		if (gdev->cdev[i]->dev.driver_data) {
+			rc = -EINVAL;
+			goto error;
+		}
 	}
+	for (i = 0; i < argc; i++)
+		gdev->cdev[i]->dev.driver_data = gdev;
+	del_drvdata = 1;
 
 	*gdev = (struct ccwgroup_device) {
 		.creator_id = creator_id,
@@ -212,9 +224,11 @@
 	device_unregister(&gdev->dev);
 error:
 	for (i = 0; i < argc; i++)
-		if (gdev->cdev[i])
+		if (gdev->cdev[i]) {
 			put_device(&gdev->cdev[i]->dev);
-
+			if (del_drvdata)
+				gdev->cdev[i]->dev.driver_data = NULL;
+		}
 	kfree(gdev);
 
 	return rc;
@@ -399,40 +413,14 @@
 __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
 {
 	struct ccwgroup_device *gdev;
-	struct list_head *entry;
-	struct device *dev;
-	int i, found;
-
-	/*
-	 * Find groupdevice cdev belongs to.
-	 * Unfortunately, we can't use bus_for_each_dev() because of the
-	 * semaphore (and return value of fn() is int).
-	 */
-	if (!get_bus(&ccwgroup_bus_type))
-		return NULL;
-
-	gdev = NULL;
-	down_read(&ccwgroup_bus_type.subsys.rwsem);
 
-	list_for_each(entry, &ccwgroup_bus_type.devices.list) {
-		dev = get_device(container_of(entry, struct device, bus_list));
-		found = 0;
-		if (!dev)
-			continue;
-		gdev = to_ccwgroupdev(dev);
-		for (i = 0; i < gdev->count && (!found); i++) {
-			if (gdev->cdev[i] == cdev)
-				found = 1;
-		}
-		if (found)
-			break;
-		put_device(dev);
-		gdev = NULL;
+	if (cdev->dev.driver_data) {
+		gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
+		if (get_device(&gdev->dev))
+			return gdev;
+		return NULL;
 	}
-	up_read(&ccwgroup_bus_type.subsys.rwsem);
-	put_bus(&ccwgroup_bus_type);
-
-	return gdev;
+	return NULL;
 }
 
 void
diff -Nru a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
--- a/drivers/s390/cio/css.h	Sat Apr  3 19:38:57 2004
+++ b/drivers/s390/cio/css.h	Sat Apr  3 19:38:57 2004
@@ -82,6 +82,7 @@
 		unsigned int dosense:1;	    /* delayed SENSE required */
 		unsigned int doverify:1;    /* delayed path verification */
 		unsigned int donotify:1;    /* call notify function */
+		unsigned int recog_done:1;  /* dev. recog. complete */
 	} __attribute__((packed)) flags;
 	unsigned long intparm;	/* user interruption parameter */
 	struct qdio_irq *qdio_data;
diff -Nru a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
--- a/drivers/s390/cio/device.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/s390/cio/device.c	Sat Apr  3 19:38:54 2004
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/cio/device.c
  *  bus driver for ccw devices
- *   $Revision: 1.107 $
+ *   $Revision: 1.110 $
  *
  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
  *			 IBM Corporation
@@ -263,10 +263,10 @@
 
 	if (!cdev)
 		return -ENODEV;
-	if (!cdev->online)
+	if (!cdev->online || !cdev->drv)
 		return -EINVAL;
 
-	if (cdev->drv && cdev->drv->set_offline) {
+	if (cdev->drv->set_offline) {
 		ret = cdev->drv->set_offline(cdev);
 		if (ret != 0)
 			return ret;
@@ -292,7 +292,7 @@
 
 	if (!cdev)
 		return -ENODEV;
-	if (cdev->online)
+	if (cdev->online || !cdev->drv)
 		return -EINVAL;
 
 	spin_lock_irq(cdev->ccwlock);
@@ -307,8 +307,7 @@
 	}
 	if (cdev->private->state != DEV_STATE_ONLINE)
 		return -ENODEV;
-	if (!cdev->drv || !cdev->drv->set_online ||
-	    cdev->drv->set_online(cdev) == 0) {
+	if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) {
 		cdev->online = 1;
 		return 0;
 	}
@@ -327,7 +326,7 @@
 online_store (struct device *dev, const char *buf, size_t count)
 {
 	struct ccw_device *cdev = to_ccwdev(dev);
-	int i, force;
+	int i, force, ret;
 	char *tmp;
 
 	if (atomic_compare_and_swap(0, 1, &cdev->private->onoff))
@@ -347,29 +346,46 @@
 	if (i == 1) {
 		/* Do device recognition, if needed. */
 		if (cdev->id.cu_type == 0) {
-			ccw_device_recognition(cdev);
+			ret = ccw_device_recognition(cdev);
+			if (ret) {
+				printk(KERN_WARNING"Couldn't start recognition "
+				       "for device %s (ret=%d)\n",
+				       cdev->dev.bus_id, ret);
+				goto out;
+			}
 			wait_event(cdev->private->wait_q,
-				   dev_fsm_final_state(cdev));
+				   cdev->private->flags.recog_done);
 		}
-		ccw_device_set_online(cdev);
+		if (cdev->drv && cdev->drv->set_online)
+			ccw_device_set_online(cdev);
 	} else if (i == 0) {
 		if (cdev->private->state == DEV_STATE_DISCONNECTED)
 			ccw_device_remove_disconnected(cdev);
-		else
+		else if (cdev->drv && cdev->drv->set_offline)
 			ccw_device_set_offline(cdev);
 	}
 	if (force && cdev->private->state == DEV_STATE_BOXED) {
-		int ret;
 		ret = ccw_device_stlck(cdev);
-		if (ret)
+		if (ret) {
+			printk(KERN_WARNING"ccw_device_stlck for device %s "
+			       "returned %d!\n", cdev->dev.bus_id, ret);
 			goto out;
+		}
 		/* Do device recognition, if needed. */
 		if (cdev->id.cu_type == 0) {
-			ccw_device_recognition(cdev);
+			cdev->private->state = DEV_STATE_NOT_OPER;
+			ret = ccw_device_recognition(cdev);
+			if (ret) {
+				printk(KERN_WARNING"Couldn't start recognition "
+				       "for device %s (ret=%d)\n",
+				       cdev->dev.bus_id, ret);
+				goto out;
+			}
 			wait_event(cdev->private->wait_q,
-				   dev_fsm_final_state(cdev));
+				   cdev->private->flags.recog_done);
 		}
-		ccw_device_set_online(cdev);
+		if (cdev->drv && cdev->drv->set_online)
+			ccw_device_set_online(cdev);
 	}
 	out:
 	if (cdev->drv)
@@ -530,7 +546,9 @@
 		       __func__, sch->dev.bus_id);
 	put_device(&cdev->dev);
 out:
+	cdev->private->flags.recog_done = 1;
 	put_device(&sch->dev);
+	wake_up(&cdev->private->wait_q);
 }
 
 static void
@@ -555,10 +573,13 @@
 {
 	struct subchannel *sch;
 
-	if (css_init_done == 0)
+	if (css_init_done == 0) {
+		cdev->private->flags.recog_done = 1;
 		return;
+	}
 	switch (cdev->private->state) {
 	case DEV_STATE_NOT_OPER:
+		cdev->private->flags.recog_done = 1;
 		/* Remove device found not operational. */
 		if (!get_device(&cdev->dev))
 			break;
diff -Nru a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
--- a/drivers/s390/cio/device_fsm.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/s390/cio/device_fsm.c	Sat Apr  3 19:38:43 2004
@@ -148,6 +148,7 @@
 	struct subchannel *sch;
 
 	sch = to_subchannel(cdev->dev.parent);
+	cdev->private->flags.recog_done = 1;
 	/*
 	 * Check if cu type and device type still match. If
 	 * not, it is certainly another device and we have to
@@ -217,6 +218,7 @@
 		__recover_lost_chpids(sch, old_lpm);
 	if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
 		if (state == DEV_STATE_NOT_OPER) {
+			cdev->private->flags.recog_done = 1;
 			cdev->private->state = DEV_STATE_DISCONNECTED;
 			return;
 		}
@@ -393,6 +395,7 @@
 	 * timeout (or if sense pgid during path verification detects the device
 	 * is locked, as may happen on newer devices).
 	 */
+	cdev->private->flags.recog_done = 0;
 	cdev->private->state = DEV_STATE_SENSE_ID;
 	ccw_device_sense_id_start(cdev);
 	return 0;
@@ -728,6 +731,9 @@
 	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
 		if (cdev->handler)
 			cdev->handler (cdev, 0, irb);
+		if (irb->scsw.cc == 1)
+			/* Basic sense hasn't started. Try again. */
+			ccw_device_do_sense(cdev, irb);
 		return;
 	}
 	/* Add basic sense info to irb. */
@@ -825,6 +831,8 @@
 	    		(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
 		if (cdev->handler)
 			cdev->handler (cdev, 0, irb);
+		if (irb->scsw.cc == 1)
+			goto call_handler;
 		return;
 	}
 	/*
@@ -838,6 +846,7 @@
 		}
 		return;
 	}
+call_handler:
 	/* Iff device is idle, reset timeout. */
 	sch = to_subchannel(cdev->dev.parent);
 	if (!stsch(sch->irq, &sch->schib))
@@ -905,6 +914,8 @@
 		/* Check for unsolicited interrupt. */
 		if (irb->scsw.stctl ==
 		    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
+			/* FIXME: we should restart stlck here, but this
+			 * is extremely unlikely ... */
 			goto out_wakeup;
 
 		ccw_device_accumulate_irb(cdev, irb);
diff -Nru a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
--- a/drivers/s390/cio/device_ops.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/s390/cio/device_ops.c	Sat Apr  3 19:38:54 2004
@@ -79,7 +79,8 @@
 	if (cdev->private->state == DEV_STATE_NOT_OPER)
 		return -ENODEV;
 	if (cdev->private->state != DEV_STATE_ONLINE ||
-	    sch->schib.scsw.actl != 0 ||
+	    ((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
+	     !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
 	    cdev->private->flags.doverify)
 		return -EBUSY;
 	ret = cio_set_options (sch, flags);
@@ -347,7 +348,9 @@
 	cdev->handler = ccw_device_wake_up;
 	if (cdev->private->state != DEV_STATE_ONLINE)
 		ret = -ENODEV;
-	else if (sch->schib.scsw.actl != 0 || cdev->private->flags.doverify)
+	else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
+		  !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
+		 cdev->private->flags.doverify)
 		ret = -EBUSY;
 	else
 		/* 0x00D9C4C3 == ebcdic "RDC" */
@@ -414,7 +417,9 @@
 	cdev->handler = ccw_device_wake_up;
 	if (cdev->private->state != DEV_STATE_ONLINE)
 		ret = -ENODEV;
-	else if (sch->schib.scsw.actl != 0 || cdev->private->flags.doverify)
+	else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
+		  !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
+		 cdev->private->flags.doverify)
 		ret = -EBUSY;
 	else
 		/* 0x00D9C3C4 == ebcdic "RCD" */
@@ -441,12 +446,12 @@
 }
 
 /*
- * Try to issue an unconditional reserve on a boxed device.
+ * Try to break the lock on a boxed device.
  */
 int
 ccw_device_stlck(struct ccw_device *cdev)
 {
-	char buf[32];
+	void *buf, *buf2;
 	unsigned long flags;
 	struct subchannel *sch;
 	int ret;
@@ -462,16 +467,30 @@
 	CIO_TRACE_EVENT(2, "stl lock");
 	CIO_TRACE_EVENT(2, cdev->dev.bus_id);
 
+	buf = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	buf2 = kmalloc(32*sizeof(char), GFP_DMA|GFP_KERNEL);
+	if (!buf2) {
+		kfree(buf);
+		return -ENOMEM;
+	}
 	spin_lock_irqsave(&sch->lock, flags);
 	ret = cio_enable_subchannel(sch, 3);
 	if (ret)
 		goto out_unlock;
-	/* Setup ccw. This cmd code seems not to be in use elsewhere. */
+	/*
+	 * Setup ccw. We chain an unconditional reserve and a release so we
+	 * only break the lock.
+	 */
 	cdev->private->iccws[0].cmd_code = CCW_CMD_STLCK;
 	cdev->private->iccws[0].cda = (__u32) __pa(buf);
 	cdev->private->iccws[0].count = 32;
-	cdev->private->iccws[0].flags = CCW_FLAG_SLI;
-
+	cdev->private->iccws[0].flags = CCW_FLAG_CC;
+	cdev->private->iccws[1].cmd_code = CCW_CMD_RELEASE;
+	cdev->private->iccws[1].cda = (__u32) __pa(buf2);
+	cdev->private->iccws[1].count = 32;
+	cdev->private->iccws[1].flags = 0;
 	ret = cio_start(sch, cdev->private->iccws, 0);
 	if (ret) {
 		cio_disable_subchannel(sch); //FIXME: return code?
@@ -486,10 +505,13 @@
 	     (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
 	    (cdev->private->irb.scsw.cstat != 0))
 		ret = -EIO;
-
 	/* Clear irb. */
 	memset(&cdev->private->irb, 0, sizeof(struct irb));
 out_unlock:
+	if (buf)
+		kfree(buf);
+	if (buf2)
+		kfree(buf2);
 	spin_unlock_irqrestore(&sch->lock, flags);
 	return ret;
 }
diff -Nru a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
--- a/drivers/s390/cio/device_status.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/s390/cio/device_status.c	Sat Apr  3 19:38:43 2004
@@ -99,7 +99,7 @@
 static inline int
 ccw_device_accumulate_esw_valid(struct irb *irb)
 {
-	if (irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
+	if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
 		return 0;
 	if (irb->scsw.stctl == 
 	    		(SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
diff -Nru a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
--- a/drivers/s390/cio/qdio.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/s390/cio/qdio.c	Sat Apr  3 19:38:44 2004
@@ -56,7 +56,7 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-#define VERSION_QDIO_C "$Revision: 1.74 $"
+#define VERSION_QDIO_C "$Revision: 1.78 $"
 
 /****************** MODULE PARAMETER VARIABLES ********************/
 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -545,6 +545,7 @@
 qdio_kick_outbound_q(struct qdio_q *q)
 {
 	int result;
+	char dbf_text[15];
 
 	QDIO_DBF_TEXT4(0,trace,"kickoutq");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
@@ -552,15 +553,75 @@
 	if (!q->siga_out)
 		return;
 
-	result=qdio_siga_output(q);
+	/* here's the story with cc=2 and busy bit set (thanks, Rick):
+	 * VM's CP could present us cc=2 and busy bit set on SIGA-write
+	 * during reconfiguration of their Guest LAN (only in HIPERS mode,
+	 * QDIO mode is asynchronous -- cc=2 and busy bit there will take
+	 * the queues down immediately; and not being under VM we have a
+	 * problem on cc=2 and busy bit set right away).
+	 *
+	 * Therefore qdio_siga_output will try for a short time constantly,
+	 * if such a condition occurs. If it doesn't change, it will
+	 * increase the busy_siga_counter and save the timestamp, and
+	 * schedule the queue for later processing (via mark_q, using the
+	 * queue tasklet). __qdio_outbound_processing will check out the
+	 * counter. If non-zero, it will call qdio_kick_outbound_q as often
+	 * as the value of the counter. This will attempt further SIGA
+	 * instructions. For each successful SIGA, the counter is
+	 * decreased, for failing SIGAs the counter remains the same, after
+	 * all.
+	 * After some time of no movement, qdio_kick_outbound_q will
+	 * finally fail and reflect corresponding error codes to call
+	 * the upper layer module and have it take the queues down.
+	 *
+	 * Note that this is a change from the original HiperSockets design
+	 * (saying cc=2 and busy bit means take the queues down), but in
+	 * these days Guest LAN didn't exist... excessive cc=2 with busy bit
+	 * conditions will still take the queues down, but the threshold is
+	 * higher due to the Guest LAN environment.
+	 */
 
-	if (!result)
-		return;
 
-	if (q->siga_error)
-		q->error_status_flags|=QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR;
-	q->error_status_flags |= QDIO_STATUS_LOOK_FOR_ERROR;
-	q->siga_error=result;
+	result=qdio_siga_output(q);
+
+		switch (result) {
+		case 0:
+		/* went smooth this time, reset timestamp */
+			QDIO_DBF_TEXT3(0,trace,"cc2reslv");
+			sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
+				atomic_read(&q->busy_siga_counter));
+			QDIO_DBF_TEXT3(0,trace,dbf_text);
+			q->timing.busy_start=0;
+			break;
+		case (2|QDIO_SIGA_ERROR_B_BIT_SET):
+			/* cc=2 and busy bit: */
+		atomic_inc(&q->busy_siga_counter);
+
+			/* if the last siga was successful, save
+			 * timestamp here */
+			if (!q->timing.busy_start)
+				q->timing.busy_start=NOW;
+
+			/* if we're in time, don't touch error_status_flags
+			 * and siga_error */
+			if (NOW-q->timing.busy_start<QDIO_BUSY_BIT_GIVE_UP) {
+				qdio_mark_q(q);
+				break;
+			}
+			QDIO_DBF_TEXT2(0,trace,"cc2REPRT");
+			sprintf(dbf_text,"%4x%2x%2x",q->irq,q->q_no,
+				atomic_read(&q->busy_siga_counter));
+			QDIO_DBF_TEXT3(0,trace,dbf_text);
+			/* else fallthrough and report error */
+		default:
+			/* for plain cc=1, 2 or 3: */
+			if (q->siga_error)
+				q->error_status_flags|=
+					QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR;
+			q->error_status_flags|=
+				QDIO_STATUS_LOOK_FOR_ERROR;
+			q->siga_error=result;
+		}
 }
 
 inline static void
@@ -599,6 +660,8 @@
 static inline void
 __qdio_outbound_processing(struct qdio_q *q)
 {
+	int siga_attempts;
+
 	QDIO_DBF_TEXT4(0,trace,"qoutproc");
 	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
 
@@ -619,6 +682,14 @@
 	perf_stats.tl_runs++;
 #endif /* QDIO_PERFORMANCE_STATS */
 
+	/* see comment in qdio_kick_outbound_q */
+	siga_attempts=atomic_read(&q->busy_siga_counter);
+	while (siga_attempts) {
+		atomic_dec(&q->busy_siga_counter);
+		qdio_kick_outbound_q(q);
+		siga_attempts--;
+	}
+
 	if (qdio_has_outbound_q_moved(q))
 		qdio_kick_outbound_handler(q);
 
@@ -1368,6 +1439,10 @@
 			((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing:
 			 &qdio_inbound_processing);
 
+		/* actually this is not used for inbound queues. yet. */
+		atomic_set(&q->busy_siga_counter,0);
+		q->timing.busy_start=0;
+
 /*		for (j=0;j<QDIO_STATS_NUMBER;j++)
 			q->timing.last_transfer_times[j]=(qdio_get_micros()/
 							  QDIO_STATS_NUMBER)*j;
@@ -1432,6 +1507,9 @@
 		q->tasklet.func=(void(*)(unsigned long))
 			&qdio_outbound_processing;
 
+		atomic_set(&q->busy_siga_counter,0);
+		q->timing.busy_start=0;
+
 		/* fill in slib */
 		if (i>0) irq_ptr->output_qs[i-1]->slib->nsliba=
 				 (unsigned long)(q->slib);
@@ -2134,7 +2212,7 @@
 	QDIO_DBF_TEXT0(0,setup,dbf_text);
 
 	rc = qdio_shutdown(cdev, how);
-	if (rc == 0)
+	if ((rc == 0) || (rc == -EINPROGRESS))
 		rc = qdio_free(cdev);
 	return rc;
 }
@@ -2145,6 +2223,7 @@
 	struct qdio_irq *irq_ptr;
 	int i;
 	int result = 0;
+	int rc;
 	unsigned long flags;
 	int timeout;
 	char dbf_text[15];
@@ -2191,27 +2270,23 @@
 			result=-EINPROGRESS;
 	}
 
-	if (result)
-		goto out;
-
 	/* cleanup subchannel */
 	spin_lock_irqsave(get_ccwdev_lock(cdev),flags);
 	if (how&QDIO_FLAG_CLEANUP_USING_CLEAR) {
-		result = ccw_device_clear(cdev, QDIO_DOING_CLEANUP);
+		rc = ccw_device_clear(cdev, QDIO_DOING_CLEANUP);
 		timeout=QDIO_CLEANUP_CLEAR_TIMEOUT;
 	} else if (how&QDIO_FLAG_CLEANUP_USING_HALT) {
-		result = ccw_device_halt(cdev, QDIO_DOING_CLEANUP);
+		rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP);
 		timeout=QDIO_CLEANUP_HALT_TIMEOUT;
 	} else { /* default behaviour */
-		result = ccw_device_halt(cdev, QDIO_DOING_CLEANUP);
+		rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP);
 		timeout=QDIO_CLEANUP_HALT_TIMEOUT;
 	}
-	if (result == -ENODEV) {
+	if (rc == -ENODEV) {
 		/* No need to wait for device no longer present. */
 		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
-		result = 0; /* No error. */
 		spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
-	} else if (result == 0) {
+	} else if (rc == 0) {
 		qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP);
 		ccw_device_set_timeout(cdev, timeout);
 		spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags);
@@ -2223,6 +2298,7 @@
 		QDIO_PRINT_INFO("ccw_device_{halt,clear} returned %d for "
 				"device %s\n", result, cdev->dev.bus_id);
 		spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+		result = rc;
 		goto out;
 	}
 	if (irq_ptr->is_thinint_irq) {
diff -Nru a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
--- a/drivers/s390/cio/qdio.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/s390/cio/qdio.h	Sat Apr  3 19:38:41 2004
@@ -1,7 +1,7 @@
 #ifndef _CIO_QDIO_H
 #define _CIO_QDIO_H
 
-#define VERSION_CIO_QDIO_H "$Revision: 1.22 $"
+#define VERSION_CIO_QDIO_H "$Revision: 1.23 $"
 
 //#define QDIO_DBF_LIKE_HELL
 
@@ -33,7 +33,8 @@
 
 #define TIQDIO_THININT_ISC 3
 #define TIQDIO_DELAY_TARGET 0
-#define QDIO_BUSY_BIT_PATIENCE 2000 /* in microsecs */
+#define QDIO_BUSY_BIT_PATIENCE 100 /* in microsecs */
+#define QDIO_BUSY_BIT_GIVE_UP 10000000 /* 10 seconds */
 #define IQDIO_GLOBAL_LAPS 2 /* GLOBAL_LAPS are not used as we */
 #define IQDIO_GLOBAL_LAPS_INT 1 /* don't global summary */
 #define IQDIO_LOCAL_LAPS 4
@@ -599,7 +600,9 @@
 		int last_transfer_index; */
 
 		__u64 last_transfer_time;
+		__u64 busy_start;
 	} timing;
+	atomic_t busy_siga_counter;
         unsigned int queue_type;
 
 	/* leave this member at the end. won't be cleared in qdio_fill_qs */
diff -Nru a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
--- a/drivers/s390/net/ctcmain.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/s390/net/ctcmain.c	Sat Apr  3 19:38:42 2004
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.56 2004/02/27 17:53:26 mschwide Exp $
+ * $Id: ctcmain.c,v 1.58 2004/03/24 10:51:56 ptiedem Exp $
  *
  * CTC / ESCON network driver
  *
@@ -36,7 +36,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.56 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.58 $
  *
  */
 
@@ -319,7 +319,7 @@
 print_banner(void)
 {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.56 $";
+	char vbuf[] = "$Revision: 1.58 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -2067,7 +2067,8 @@
 		return;
 	}
 	
-	priv = cdev->dev.driver_data;
+	priv = ((struct ccwgroup_device *)cdev->dev.driver_data)
+		->dev.driver_data;
 
 	/* Try to extract channel from driver data. */
 	if (priv->channel[READ]->cdev == cdev)
@@ -2963,8 +2964,6 @@
 	cgdev->cdev[0]->handler = ctc_irq_handler;
 	cgdev->cdev[1]->handler = ctc_irq_handler;
 	cgdev->dev.driver_data = priv;
-	cgdev->cdev[0]->dev.driver_data = priv;
-	cgdev->cdev[1]->dev.driver_data = priv;
 
 	return 0;
 }
@@ -3043,26 +3042,13 @@
 		privptr->channel[direction]->protocol = privptr->protocol;
 		privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT;
 	}
+	/* sysfs magic */
+	SET_NETDEV_DEV(dev, &cgdev->dev);
+
 	if (ctc_netdev_register(dev) != 0) {
 		ctc_free_netdevice(dev, 1);
 		goto out;
 	}
-	/* Create symlinks. */
-	if (sysfs_create_link(&cgdev->dev.kobj, &dev->class_dev.kobj,
-			      dev->name)) {
-		ctc_netdev_unregister(dev);
-		dev->priv = 0;
-		ctc_free_netdevice(dev, 1);
-		goto out;
-	}
-	if (sysfs_create_link(&dev->class_dev.kobj, &cgdev->dev.kobj,
-			      cgdev->dev.bus_id)) {
-		sysfs_remove_link(&cgdev->dev.kobj, dev->name);
-		ctc_netdev_unregister(dev);
-		dev->priv = 0;
-		ctc_free_netdevice(dev, 1);
-		goto out;
-	}
 
 	ctc_add_attributes(&cgdev->dev);
 
@@ -3118,8 +3104,6 @@
 		channel_free(priv->channel[WRITE]);
 
 	if (ndev) {
-		sysfs_remove_link(&ndev->class_dev.kobj, cgdev->dev.bus_id);
-		sysfs_remove_link(&cgdev->dev.kobj, ndev->name);
 		ctc_netdev_unregister(ndev);
 		ndev->priv = NULL;
 		ctc_free_netdevice(ndev, 1);
diff -Nru a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
--- a/drivers/s390/net/iucv.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/s390/net/iucv.c	Sat Apr  3 19:38:41 2004
@@ -1,5 +1,5 @@
 /* 
- * $Id: iucv.c,v 1.24 2004/02/05 14:16:01 braunu Exp $
+ * $Id: iucv.c,v 1.27 2004/03/22 07:43:43 braunu Exp $
  *
  * IUCV network driver
  *
@@ -29,7 +29,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.24 $
+ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.27 $
  *
  */
 
@@ -351,7 +351,7 @@
 static void
 iucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.24 $";
+	char vbuf[] = "$Revision: 1.27 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
@@ -374,14 +374,14 @@
 {
 	int ret;
 
+	if (iucv_external_int_buffer)
+		return 0;
+
 	if (!MACHINE_IS_VM) {
 		printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n");
 		return -EPROTONOSUPPORT;
 	}
 
-	if (iucv_external_int_buffer)
-		return 0;
-
 	ret = bus_register(&iucv_bus);
 	if (ret != 0) {
 		printk(KERN_ERR "IUCV: failed to register bus.\n");
@@ -670,10 +670,12 @@
 	ulong b2f0_result = 0x0deadbeef;
 
 	iucv_debug(1, "entering");
+	preempt_disable();
 	if (smp_processor_id() == 0)
 		iucv_declare_buffer_cpu0(&b2f0_result);
 	else
 		smp_call_function(iucv_declare_buffer_cpu0, &b2f0_result, 0, 1);
+	preempt_enable();
 	iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
 	if (b2f0_result == 0x0deadbeef)
 	    b2f0_result = 0xaa;
@@ -692,11 +694,13 @@
 {
 	iucv_debug(1, "entering");
 	if (declare_flag) {
+		preempt_disable();
 		if (smp_processor_id() == 0)
 			iucv_retrieve_buffer_cpu0(0);
 		else
 			smp_call_function(iucv_retrieve_buffer_cpu0, 0, 0, 1);
 		declare_flag = 0;
+		preempt_enable();
 	}
 	iucv_debug(1, "exiting");
 	return 0;
@@ -826,7 +830,7 @@
 			memset (new_handler->id.mask, 0xFF,
 				sizeof (new_handler->id.mask));
 		}
-		memset (new_handler->id.mask, 0x00,
+		memset (new_handler->id.userid, 0x00,
 			sizeof (new_handler->id.userid));
 	}
 	/* fill in the rest of handler */
@@ -2216,10 +2220,12 @@
 	} u;
 
 	u.param = SetMaskFlag;
+	preempt_disable();
 	if (smp_processor_id() == 0)
 		iucv_setmask_cpu0(&u);
 	else
 		smp_call_function(iucv_setmask_cpu0, &u, 0, 1);
+	preempt_enable();
 
 	return u.result;
 }
@@ -2519,10 +2525,6 @@
 
 /**
  * Export all public stuff
- * FIXME: I have commented out all the functions that
- * 	  are not used in netiucv. Is anyone else
- * 	  using them or should some of them be made
- * 	  static / removed? pls review. Arnd
  */
 EXPORT_SYMBOL (iucv_bus);
 EXPORT_SYMBOL (iucv_root);
diff -Nru a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
--- a/drivers/s390/net/lcs.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/s390/net/lcs.c	Sat Apr  3 19:38:41 2004
@@ -11,7 +11,7 @@
  *			  Frank Pavlic (pavlic@de.ibm.com) and
  *		 	  Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *    $Revision: 1.67 $	 $Date: 2004/02/26 18:26:50 $
+ *    $Revision: 1.72 $	 $Date: 2004/03/22 09:34:27 $
  *
  * 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
@@ -58,9 +58,10 @@
 /**
  * initialization string for output
  */
-#define VERSION_LCS_C  "$Revision: 1.67 $"
+#define VERSION_LCS_C  "$Revision: 1.72 $"
 
 static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
+static char debug_buffer[255];
 
 /**
  * Some prototypes.
@@ -112,7 +113,7 @@
 {
 	int cnt;
 
-	LCS_DBF_TEXT(3, setup, "ichalloc");
+	LCS_DBF_TEXT(2, setup, "ichalloc");
 	for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) {
 		/* alloc memory fo iobuffer */
 		channel->iob[cnt].data = (void *)
@@ -124,7 +125,7 @@
 	}
 	if (cnt < LCS_NUM_BUFFS) {
 		/* Not all io buffers could be allocated. */
-		LCS_DBF_TEXT(3, setup, "echalloc");
+		LCS_DBF_TEXT(2, setup, "echalloc");
 		while (cnt-- > 0)
 			kfree(channel->iob[cnt].data);
 		return -ENOMEM;
@@ -140,7 +141,7 @@
 {
 	int cnt;
 
-	LCS_DBF_TEXT(3, setup, "ichfree");
+	LCS_DBF_TEXT(2, setup, "ichfree");
 	for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) {
 		if (channel->iob[cnt].data != NULL)
 			kfree(channel->iob[cnt].data);
@@ -148,6 +149,30 @@
 	}
 }
 
+/*
+ * Cleanup channel.
+ */
+static void
+lcs_cleanup_channel(struct lcs_channel *channel)
+{
+	LCS_DBF_TEXT(3, setup, "cleanch");
+	/* Kill write channel tasklets. */
+	tasklet_kill(&channel->irq_tasklet);
+	/* Free channel buffers. */
+	lcs_free_channel(channel);
+}
+
+/**
+ * LCS free memory for card and channels.
+ */
+static void
+lcs_free_card(struct lcs_card *card)
+{
+	LCS_DBF_TEXT(2, setup, "remcard");
+	LCS_DBF_HEX(2, setup, &card, sizeof(void*));
+	kfree(card);
+}
+
 /**
  * LCS alloc memory for card and channels
  */
@@ -155,25 +180,34 @@
 lcs_alloc_card(void)
 {
 	struct lcs_card *card;
+	int rc;
+
+	LCS_DBF_TEXT(2, setup, "alloclcs");
 
-	LCS_DBF_TEXT(3, setup, "alloclcs");
 	card = kmalloc(sizeof(struct lcs_card), GFP_KERNEL | GFP_DMA);
 	if (card == NULL)
 		return NULL;
 	memset(card, 0, sizeof(struct lcs_card));
 	card->lan_type = LCS_FRAME_TYPE_AUTO;
 	card->lancmd_timeout = LCS_LANCMD_TIMEOUT_DEFAULT;
-	return card;
-}
+	/* Allocate io buffers for the read channel. */
+	rc = lcs_alloc_channel(&card->read);
+	if (rc){
+		LCS_DBF_TEXT(2, setup, "iccwerr");
+		lcs_free_card(card);
+		return NULL;
+	}
+	/* Allocate io buffers for the write channel. */
+	rc = lcs_alloc_channel(&card->write);
+	if (rc) {
+		LCS_DBF_TEXT(2, setup, "iccwerr");
+		lcs_cleanup_channel(&card->read);
+		lcs_free_card(card);
+		return NULL;
+	}
 
-/**
- * LCS free memory for card and channels.
- */
-static void
-lcs_free_card(struct lcs_card *card)
-{
-	LCS_DBF_TEXT(2, setup, "remcard");
-	kfree(card);
+	LCS_DBF_HEX(2, setup, &card, sizeof(void*));
+	return card;
 }
 
 /*
@@ -218,25 +252,17 @@
 	card->read.buf_idx = 0;
 }
 
-static int
+static void
 lcs_setup_read(struct lcs_card *card)
 {
-	int rc;
+	LCS_DBF_TEXT(3, setup, "initread");
 
-	LCS_DBF_TEXT(3, setup, "readirq");
-	/* Allocate io buffers for the read channel. */
-	rc = lcs_alloc_channel(&card->read);
-	if (rc){
-		LCS_DBF_TEXT(3, setup, "iccwerr");
-		return rc;
-	}
 	lcs_setup_read_ccws(card);
 	/* Initialize read channel tasklet. */
 	card->read.irq_tasklet.data = (unsigned long) &card->read;
 	card->read.irq_tasklet.func = lcs_tasklet;
 	/* Initialize waitqueue. */
 	init_waitqueue_head(&card->read.wait_q);
-	return 0;
 }
 
 /*
@@ -247,7 +273,7 @@
 {
 	int cnt;
 
-	LCS_DBF_TEXT(2, setup, "iwritccw");
+	LCS_DBF_TEXT(3, setup, "iwritccw");
 	/* Setup write ccws. */
 	memset(card->write.ccws, 0, sizeof(struct ccw1) * LCS_NUM_BUFFS + 1);
 	for (cnt = 0; cnt < LCS_NUM_BUFFS; cnt++) {
@@ -273,61 +299,32 @@
 	card->write.buf_idx = 0;
 }
 
-static int
+static void
 lcs_setup_write(struct lcs_card *card)
 {
-	int rc;
+	LCS_DBF_TEXT(3, setup, "initwrit");
 
-	LCS_DBF_TEXT(3, setup, "writeirq");
-	/* Allocate io buffers for the write channel. */
-	rc = lcs_alloc_channel(&card->write);
-	if (rc) {
-		LCS_DBF_TEXT(3, setup, "iccwerr");
-		return rc;
-	}
 	lcs_setup_write_ccws(card);
 	/* Initialize write channel tasklet. */
 	card->write.irq_tasklet.data = (unsigned long) &card->write;
 	card->write.irq_tasklet.func = lcs_tasklet;
 	/* Initialize waitqueue. */
 	init_waitqueue_head(&card->write.wait_q);
-	return 0;
 }
 
-/*
- * Cleanup channel.
- */
-static void
-lcs_cleanup_channel(struct lcs_channel *channel)
-{
-	LCS_DBF_TEXT(3, setup, "cleanch");
-	/* Kill write channel tasklets. */
-	tasklet_kill(&channel->irq_tasklet);
-	/* Free channel buffers. */
-	lcs_free_channel(channel);
-}
+
 
 /**
  * Initialize channels,card and state machines.
  */
-static int
+static void
 lcs_setup_card(struct lcs_card *card)
 {
-	int rc;
-
-	LCS_DBF_TEXT(3, setup, "initcard");
+	LCS_DBF_TEXT(2, setup, "initcard");
+	LCS_DBF_HEX(2, setup, &card, sizeof(void*));
 
-	rc = lcs_setup_read(card);
-	if (rc) {
-		PRINT_ERR("Could not initialize read channel\n");
-		return rc;
-	}
-	rc = lcs_setup_write(card);
-	if (rc) {
-		PRINT_ERR("Could not initialize write channel\n");
-		lcs_cleanup_channel(&card->read);
-		return rc;
-	}
+	lcs_setup_read(card);
+	lcs_setup_write(card);
 	/* Set cards initial state. */
 	card->state = DEV_STATE_DOWN;
 	card->tx_buffer = NULL;
@@ -342,7 +339,6 @@
 	INIT_LIST_HEAD(&card->ipm_list);
 #endif
 	INIT_LIST_HEAD(&card->lancmd_waiters);
-	return 0;
 }
 
 /**
@@ -355,6 +351,7 @@
 	struct lcs_ipm_list *ipm_list;
 
 	LCS_DBF_TEXT(3, setup, "cleancrd");
+	LCS_DBF_HEX(2,setup,&card,sizeof(void*));
 #ifdef	CONFIG_IP_MULTICAST
 	/* Free multicast list. */
 	list_for_each_safe(l, n, &card->ipm_list) {
@@ -376,12 +373,10 @@
 static int
 lcs_start_channel(struct lcs_channel *channel)
 {
-	char dbf_text[15];
 	unsigned long flags;
 	int rc;
 
-	sprintf(dbf_text,"ssch%s", channel->ccwdev->dev.bus_id);
-	LCS_DBF_TEXT(4, trace, dbf_text);
+	LCS_DBF_TEXT_(4,trace,"ssch%s", channel->ccwdev->dev.bus_id);
 	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
 	rc = ccw_device_start(channel->ccwdev,
 			      channel->ccws + channel->io_idx, 0, 0,
@@ -390,37 +385,56 @@
 		channel->state = CH_STATE_RUNNING;
 	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 	if (rc) {
-		sprintf(dbf_text,"essc%s", channel->ccwdev->dev.bus_id);
-		LCS_DBF_TEXT(4, trace, dbf_text);
+		LCS_DBF_TEXT_(4,trace,"essh%s", channel->ccwdev->dev.bus_id);
 		PRINT_ERR("Error in starting channel, rc=%d!\n", rc);
 	}
 	return rc;
 }
 
+static int
+lcs_clear_channel(struct lcs_channel *channel)
+{
+	unsigned long flags;
+	int rc;
+
+	LCS_DBF_TEXT(4,trace,"clearch");
+	LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id);
+	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+	rc = ccw_device_clear(channel->ccwdev, (addr_t) channel);
+	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+	if (rc) {
+		LCS_DBF_TEXT_(4,trace,"ecsc%s", channel->ccwdev->dev.bus_id);
+		return rc;
+	}
+	wait_event(channel->wait_q, (channel->state == CH_STATE_CLEARED));
+	channel->state = CH_STATE_STOPPED;
+	return rc;
+}
+
+
 /**
  * Stop channel.
  */
 static int
 lcs_stop_channel(struct lcs_channel *channel)
 {
-	char dbf_text[15];
 	unsigned long flags;
 	int rc;
 
 	if (channel->state == CH_STATE_STOPPED)
 		return 0;
-	sprintf(dbf_text,"hsch%s", channel->ccwdev->dev.bus_id);
-	LCS_DBF_TEXT(4, trace, dbf_text);
+	LCS_DBF_TEXT(4,trace,"haltsch");
+	LCS_DBF_TEXT_(4,trace,"%s", channel->ccwdev->dev.bus_id);
 	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
 	rc = ccw_device_halt(channel->ccwdev, (addr_t) channel);
 	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
 	if (rc) {
-		sprintf(dbf_text,"ehsc%s", channel->ccwdev->dev.bus_id);
-		LCS_DBF_TEXT(4, trace, dbf_text);
+		LCS_DBF_TEXT_(4,trace,"ehsc%s", channel->ccwdev->dev.bus_id);
 		return rc;
 	}
 	/* Asynchronous halt initialted. Wait for its completion. */
 	wait_event(channel->wait_q, (channel->state == CH_STATE_HALTED));
+	lcs_clear_channel(channel);
 	return 0;
 }
 
@@ -464,6 +478,7 @@
 {
 	int index;
 
+	LCS_DBF_TEXT(5, trace, "_getbuff");
 	index = channel->io_idx;
 	do {
 		if (channel->iob[index].state == BUF_STATE_EMPTY) {
@@ -481,6 +496,7 @@
 	struct lcs_buffer *buffer;
 	unsigned long flags;
 
+	LCS_DBF_TEXT(5, trace, "getbuff");
 	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
 	buffer = __lcs_get_buffer(channel);
 	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
@@ -493,19 +509,16 @@
 static int
 __lcs_resume_channel(struct lcs_channel *channel)
 {
-	char dbf_text[15];
 	int rc;
 
 	if (channel->state != CH_STATE_SUSPENDED)
 		return 0;
 	if (channel->ccws[channel->io_idx].flags & CCW_FLAG_SUSPEND)
 		return 0;
-	sprintf(dbf_text,"rsch%s", channel->ccwdev->dev.bus_id);
-	LCS_DBF_TEXT(4, trace, dbf_text);
+	LCS_DBF_TEXT_(5, trace, "rsch%s", channel->ccwdev->dev.bus_id);
 	rc = ccw_device_resume(channel->ccwdev);
 	if (rc) {
-		sprintf(dbf_text,"ersc%s", channel->ccwdev->dev.bus_id);
-		LCS_DBF_TEXT(4, trace, dbf_text);
+		LCS_DBF_TEXT_(4, trace, "ersc%s", channel->ccwdev->dev.bus_id);
 		PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc);
 	} else
 		channel->state = CH_STATE_RUNNING;
@@ -521,6 +534,7 @@
 {
 	int prev, next;
 
+	LCS_DBF_TEXT(5, trace, "rdybits");
 	prev = (index - 1) & (LCS_NUM_BUFFS - 1);
 	next = (index + 1) & (LCS_NUM_BUFFS - 1);
 	/* Check if we may clear the suspend bit of this buffer. */
@@ -540,6 +554,7 @@
 	unsigned long flags;
 	int index, rc;
 
+	LCS_DBF_TEXT(5, trace, "rdybuff");
 	if (buffer->state != BUF_STATE_LOCKED &&
 	    buffer->state != BUF_STATE_PROCESSED)
 		BUG();
@@ -565,6 +580,7 @@
 {
 	int index, prev, next;
 
+	LCS_DBF_TEXT(5, trace, "prcsbuff");
 	if (buffer->state != BUF_STATE_READY)
 		BUG();
 	buffer->state = BUF_STATE_PROCESSED;
@@ -597,6 +613,7 @@
 {
 	unsigned long flags;
 
+	LCS_DBF_TEXT(5, trace, "relbuff");
 	if (buffer->state != BUF_STATE_LOCKED &&
 	    buffer->state != BUF_STATE_PROCESSED)
 		BUG();
@@ -614,6 +631,7 @@
 	struct lcs_buffer *buffer;
 	struct lcs_cmd *cmd;
 
+	LCS_DBF_TEXT(4, trace, "getlncmd");
 	/* Get buffer and wait if none is available. */
 	wait_event(card->write.wait_q,
 		   ((buffer = lcs_get_buffer(&card->write)) != NULL));
@@ -637,6 +655,7 @@
 	struct list_head *l, *n;
 	struct lcs_reply *reply;
 
+	LCS_DBF_TEXT(4, trace, "notiwait");
 	spin_lock(&card->lock);
 	list_for_each_safe(l, n, &card->lancmd_waiters) {
 		reply = list_entry(l, struct lcs_reply, list);
@@ -661,6 +680,7 @@
 {
 	struct lcs_reply *reply;
 
+	LCS_DBF_TEXT(4, trace, "timeout");
 	reply = (struct lcs_reply *) data;
 	list_del(&reply->list);
 	reply->received = 1;
@@ -676,8 +696,8 @@
 	struct lcs_cmd *cmd;
 	struct timer_list timer;
 	int rc;
-	char buf[16];
 
+	LCS_DBF_TEXT(4, trace, "sendcmd");
 	cmd = (struct lcs_cmd *) buffer->data;
 	cmd->sequence_no = ++card->sequence_no;
 	cmd->return_code = 0;
@@ -700,9 +720,7 @@
 	add_timer(&timer);
 	wait_event(reply.wait_q, reply.received);
 	del_timer(&timer);
-	LCS_DBF_TEXT(5, trace, "sendcmd");
-	sprintf(buf, "rc:%d", reply.rc);
-	LCS_DBF_TEXT(5, trace, buf);
+	LCS_DBF_TEXT_(4, trace, "rc:%d",reply.rc);
 	return reply.rc ? -EIO : 0;
 }
 
@@ -747,6 +765,7 @@
 static void
 __lcs_lanstat_cb(struct lcs_card *card, struct lcs_cmd *cmd)
 {
+	LCS_DBF_TEXT(2, trace, "statcb");
 	memcpy(card->mac, cmd->cmd.lcs_lanstat_cmd.mac_addr, LCS_MAC_LENGTH);
 }
 
@@ -756,7 +775,7 @@
 	struct lcs_buffer *buffer;
 	struct lcs_cmd *cmd;
 
-	LCS_DBF_TEXT(2, trace, "cmdstat");
+	LCS_DBF_TEXT(2,trace, "cmdstat");
 	buffer = lcs_get_lancmd(card, LCS_STD_CMD_SIZE);
 	cmd = (struct lcs_cmd *) buffer->data;
 	/* Setup lanstat command. */
@@ -792,6 +811,7 @@
 static void
 __lcs_send_startlan_cb(struct lcs_card *card, struct lcs_cmd *cmd)
 {
+	LCS_DBF_TEXT(2, trace, "srtlancb");
 	card->lan_type = cmd->cmd.lcs_std_cmd.lan_type;
 	card->portno = cmd->cmd.lcs_std_cmd.portno;
 }
@@ -833,6 +853,7 @@
 	cmd->cmd.lcs_qipassist.num_ip_pairs = 1;
 	memcpy(cmd->cmd.lcs_qipassist.lcs_ipass_ctlmsg.ip_mac_pair,
 	       &ipm_list->ipm, sizeof (struct lcs_ip_mac_pair));
+	LCS_DBF_TEXT_(2, trace, "%x",ipm_list->ipm.ip_addr);
 	return lcs_send_lancmd(card, buffer, NULL);
 }
 
@@ -856,6 +877,7 @@
 	cmd->cmd.lcs_qipassist.num_ip_pairs = 1;
 	memcpy(cmd->cmd.lcs_qipassist.lcs_ipass_ctlmsg.ip_mac_pair,
 	       &ipm_list->ipm, sizeof (struct lcs_ip_mac_pair));
+	LCS_DBF_TEXT_(2, trace, "%x",ipm_list->ipm.ip_addr);
 	return lcs_send_lancmd(card, buffer, NULL);
 }
 
@@ -865,6 +887,7 @@
 static void
 __lcs_check_multicast_cb(struct lcs_card *card, struct lcs_cmd *cmd)
 {
+	LCS_DBF_TEXT(2, trace, "chkmccb");
 	card->ip_assists_supported =
 		cmd->cmd.lcs_qipassist.ip_assists_supported;
 	card->ip_assists_enabled =
@@ -919,7 +942,7 @@
 	card = (struct lcs_card *) data;
 
 	daemonize("fixipm");
-	LCS_DBF_TEXT(5, trace, "fixipm");
+	LCS_DBF_TEXT(4,trace, "fixipm");
 	spin_lock(&card->lock);
 	list_for_each_safe(l, n, &card->ipm_list) {
 		ipm = list_entry(l, struct lcs_ipm_list, list);
@@ -952,6 +975,7 @@
 static void
 lcs_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev)
 {
+	LCS_DBF_TEXT(4,trace, "getmac");
 	if (dev->type == ARPHRD_IEEE802_TR)
 		ip_tr_mc_map(ipm, mac);
 	else
@@ -971,7 +995,7 @@
 	struct lcs_ipm_list *ipm, *tmp;
 	struct lcs_card *card;
 
-	LCS_DBF_TEXT(5, trace, "setmulti");
+	LCS_DBF_TEXT(4, trace, "setmulti");
 	in4_dev = in_dev_get(dev);
 	if (in4_dev == NULL)
 		return;
@@ -1033,21 +1057,18 @@
 static void
 lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
 {
-	char dbf_text[15];
 	struct lcs_card *card;
 	struct lcs_channel *channel;
 	int index;
 
-	card = (struct lcs_card *)cdev->dev.driver_data;
+	card = CARD_FROM_DEV(cdev);
 	if (card->read.ccwdev == cdev)
 		channel = &card->read;
 	else
 		channel = &card->write;
 
-	sprintf(dbf_text, "Rint%s", cdev->dev.bus_id);
-	LCS_DBF_TEXT(5, trace, dbf_text);
-	sprintf(dbf_text, "%4x%4x", irb->scsw.cstat, irb->scsw.dstat);
-	LCS_DBF_TEXT(5, trace, dbf_text);
+	LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id);
+	LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat);
 
 	/* How far in the ccw chain have we processed? */
 	if ((channel->state != CH_STATE_INIT) &&
@@ -1084,6 +1105,9 @@
 		channel->state = CH_STATE_HALTED;
 	}
 
+	if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
+		channel->state = CH_STATE_CLEARED;
+	}
 	/* Do the rest in the tasklet. */
 	tasklet_schedule(&channel->irq_tasklet);
 }
@@ -1094,7 +1118,6 @@
 static void
 lcs_tasklet(unsigned long data)
 {
-	char dbf_text[15];
 	unsigned long flags;
 	struct lcs_channel *channel;
 	struct lcs_buffer *iob;
@@ -1102,8 +1125,7 @@
 	int rc;
 
 	channel = (struct lcs_channel *) data;
-	sprintf(dbf_text, "tlet%s", channel->ccwdev->dev.bus_id);
-	LCS_DBF_TEXT(5, trace, dbf_text);
+	LCS_DBF_TEXT_(5, trace, "tlet%s",channel->ccwdev->dev.bus_id);
 
 	/* Check for processed buffers. */
 	iob = channel->iob;
@@ -1137,6 +1159,7 @@
 static void
 __lcs_emit_txbuffer(struct lcs_card *card)
 {
+	LCS_DBF_TEXT(5, trace, "emittx");
 	*(__u16 *)(card->tx_buffer->data + card->tx_buffer->count) = 0;
 	card->tx_buffer->count += 2;
 	lcs_ready_buffer(&card->write, card->tx_buffer);
@@ -1152,6 +1175,7 @@
 {
 	struct lcs_card *card;
 
+	LCS_DBF_TEXT(5, trace, "txbuffcb");
 	/* Put buffer back to pool. */
 	lcs_release_buffer(channel, buffer);
 	card = (struct lcs_card *)
@@ -1176,6 +1200,7 @@
 {
 	struct lcs_header *header;
 
+	LCS_DBF_TEXT(5, trace, "hardxmit");
 	if (skb == NULL) {
 		card->stats.tx_dropped++;
 		card->stats.tx_errors++;
@@ -1201,7 +1226,6 @@
 		/* Get new tx buffer */
 		card->tx_buffer = lcs_get_buffer(&card->write);
 		if (card->tx_buffer == NULL) {
-			netif_stop_queue(dev);
 			card->stats.tx_dropped++;
 			return -EBUSY;
 		}
@@ -1246,6 +1270,7 @@
 {
 	int rc;
 
+	LCS_DBF_TEXT(2, trace, "strtauto");
 #ifdef CONFIG_NET_ETHERNET
 	card->lan_type = LCS_FRAME_TYPE_ENET;
 	rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP);
@@ -1307,7 +1332,7 @@
 {
 	int rc = 0;
 
-	LCS_DBF_TEXT(3, setup," lcsdetct");
+	LCS_DBF_TEXT(2, setup, "lcsdetct");
 	/* start/reset card */
 	if (card->dev)
 		netif_stop_queue(card->dev);
@@ -1340,7 +1365,7 @@
 {
 	int retries;
 
-	LCS_DBF_TEXT(4, trace, "rescard");
+	LCS_DBF_TEXT(2, trace, "rescard");
 	for (retries = 0; retries < 10; retries++) {
 		if (lcs_detect(card) == 0) {
 			netif_wake_queue(card->dev);
@@ -1364,13 +1389,16 @@
 	int rc;
 
 	LCS_DBF_TEXT(3, setup, "stopcard");
+
 	if (card->read.state != CH_STATE_STOPPED &&
 	    card->write.state != CH_STATE_STOPPED &&
-	    card->state == DEV_STATE_UP)
+	    card->state == DEV_STATE_UP) {
 		rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP);
-	rc = lcs_send_shutdown(card);
+		rc = lcs_send_shutdown(card);
+	}
 	rc = lcs_stop_channels(card);
 	card->state = DEV_STATE_DOWN;
+
 	return rc;
 }
 
@@ -1492,6 +1520,7 @@
 static void
 lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd)
 {
+	LCS_DBF_TEXT(5, trace, "getctrl");
 	if (cmd->initiator == LCS_INITIATOR_LGW) {
 		switch(cmd->cmd_code) {
 		case LCS_CMD_STARTUP:
@@ -1522,6 +1551,7 @@
 {
 	struct sk_buff *skb;
 
+	LCS_DBF_TEXT(5, trace, "getskb");
 	if (card->dev == NULL ||
 	    card->state != DEV_STATE_UP)
 		/* The card isn't up. Ignore the packet. */
@@ -1619,6 +1649,7 @@
 	LCS_DBF_TEXT(2, trace, "stopdev");
 	card   = (struct lcs_card *) dev->priv;
 	netif_stop_queue(dev);
+	dev->flags &= ~IFF_UP;
 	rc = lcs_stopcard(card);
 	if (rc)
 		PRINT_ERR("Try it again!\n ");
@@ -1643,6 +1674,7 @@
 		PRINT_ERR("LCS:Error in opening device!\n");
 
 	} else {
+		dev->flags |= IFF_UP;
 		netif_wake_queue(dev);
 		card->state = DEV_STATE_UP;
 	}
@@ -1757,7 +1789,7 @@
 	if (!get_device(&ccwgdev->dev))
 		return -ENODEV;
 
-	LCS_DBF_TEXT(3, setup, "add_dev");
+	LCS_DBF_TEXT(2, setup, "add_dev");
         card = lcs_alloc_card();
         if (!card) {
                 PRINT_ERR("Allocation of lcs card failed\n");
@@ -1772,46 +1804,62 @@
 		return ret;
         }
 	ccwgdev->dev.driver_data = card;
-	ccwgdev->cdev[0]->dev.driver_data = card;
 	ccwgdev->cdev[0]->handler = lcs_irq;
-	ccwgdev->cdev[1]->dev.driver_data = card;
 	ccwgdev->cdev[1]->handler = lcs_irq;
         return 0;
 }
 
+static int
+lcs_register_netdev(struct ccwgroup_device *ccwgdev)
+{
+	struct lcs_card *card;
+
+	LCS_DBF_TEXT(2, setup, "regnetdv");
+	card = (struct lcs_card *)ccwgdev->dev.driver_data;
+	if (card->dev->reg_state != NETREG_UNINITIALIZED)
+		return 0;
+	SET_NETDEV_DEV(card->dev, &ccwgdev->dev);
+	return register_netdev(card->dev);
+}
+
 /**
  * lcs_new_device will be called by setting the group device online.
  */
+
 static int
 lcs_new_device(struct ccwgroup_device *ccwgdev)
 {
 	struct  lcs_card *card;
-	struct net_device *dev;
+	struct net_device *dev=NULL;
+	enum lcs_dev_states recover_state;
 	int rc;
 
 	card = (struct lcs_card *)ccwgdev->dev.driver_data;
 	if (!card)
 		return -ENODEV;
 
+	LCS_DBF_TEXT(2, setup, "newdev");
+	LCS_DBF_HEX(3, setup, &card, sizeof(void*));
 	card->read.ccwdev  = ccwgdev->cdev[0];
 	card->write.ccwdev = ccwgdev->cdev[1];
 
+	recover_state = card->state;
 	ccw_device_set_online(card->read.ccwdev);
 	ccw_device_set_online(card->write.ccwdev);
 
 	LCS_DBF_TEXT(3, setup, "lcsnewdv");
-	rc = lcs_setup_card(card);
-	if (rc) {
-		LCS_DBF_TEXT(3, setup, "errinit");
-		PRINT_ERR("LCS card Initialization failed\n");
-		return rc;
-	}
 
+	lcs_setup_card(card);
 	rc = lcs_detect(card);
 	if (rc) {
 		lcs_stopcard(card);
 		lcs_cleanup_card(card);
-		return -ENODEV;
+		goto out;
+	}
+	if (card->dev) {
+		LCS_DBF_TEXT(2, setup, "samedev");
+		LCS_DBF_HEX(3, setup, &card, sizeof(void*));
+		goto netdev_out;
 	}
 	switch (card->lan_type) {
 #ifdef CONFIG_NET_ETHERNET
@@ -1840,36 +1888,34 @@
 	}
 	if (!dev)
 		goto out;
-	memcpy(dev->dev_addr, card->mac, LCS_MAC_LENGTH);
 	card->dev = dev;
-	dev->priv = card;
-	dev->open = lcs_open_device;
-	dev->stop = lcs_stop_device;
-	dev->hard_start_xmit = lcs_start_xmit;
+netdev_out:
+	card->dev->priv = card;
+	card->dev->open = lcs_open_device;
+	card->dev->stop = lcs_stop_device;
+	card->dev->hard_start_xmit = lcs_start_xmit;
+	card->dev->get_stats = lcs_getstats;
+	SET_MODULE_OWNER(dev);
+	if (lcs_register_netdev(ccwgdev) != 0)
+		goto out;
+	memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
 #ifdef CONFIG_IP_MULTICAST
 	if (lcs_check_multicast_support(card))
-		dev->set_multicast_list = lcs_set_multicast_list;
+		card->dev->set_multicast_list = lcs_set_multicast_list;
 #endif
-	dev->get_stats = lcs_getstats;
-	SET_MODULE_OWNER(dev);
-	if (register_netdev(dev) != 0)
-		goto out;
-	/* Create symlinks. */
-	if (sysfs_create_link(&ccwgdev->dev.kobj, &dev->class_dev.kobj,
-			      dev->name)) {
-		unregister_netdev(dev);
-		goto out;
-	}
-	if (sysfs_create_link(&dev->class_dev.kobj, &ccwgdev->dev.kobj,
-			      ccwgdev->dev.bus_id)) {
-		sysfs_remove_link(&ccwgdev->dev.kobj, dev->name);
-		unregister_netdev(dev);
-		goto out;
-	}
-	netif_stop_queue(dev);
-	lcs_stopcard(card);
+	netif_stop_queue(card->dev);
+	if (recover_state == DEV_STATE_RECOVER) {
+		card->dev->flags |= IFF_UP;
+		netif_wake_queue(card->dev);
+		card->state = DEV_STATE_UP;
+	} else
+		lcs_stopcard(card);
+
 	return 0;
 out:
+
+	ccw_device_set_offline(card->read.ccwdev);
+	ccw_device_set_offline(card->write.ccwdev);
 	lcs_cleanup_card(card);
 	return -ENODEV;
 }
@@ -1881,6 +1927,7 @@
 lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
 {
 	struct lcs_card *card;
+	enum lcs_dev_states recover_state;
 	int ret;
 
 	LCS_DBF_TEXT(3, setup, "shtdndev");
@@ -1888,12 +1935,17 @@
 	if (!card)
 		return -ENODEV;
 
+	LCS_DBF_HEX(3, setup, &card, sizeof(void*));
+	recover_state = card->state;
+
 	ret = lcs_stop_device(card->dev);
+	ret = ccw_device_set_offline(card->read.ccwdev);
+	ret = ccw_device_set_offline(card->write.ccwdev);
+	if (recover_state == DEV_STATE_UP) {
+		card->state = DEV_STATE_RECOVER;
+	}
 	if (ret)
 		return ret;
-	sysfs_remove_link(&card->dev->class_dev.kobj, ccwgdev->dev.bus_id);
-	sysfs_remove_link(&ccwgdev->dev.kobj, card->dev->name);
-	unregister_netdev(card->dev);
 	return 0;
 }
 
@@ -1905,17 +1957,17 @@
 {
 	struct lcs_card *card;
 
-	LCS_DBF_TEXT(3, setup, "remdev");
 	card = (struct lcs_card *)ccwgdev->dev.driver_data;
 	if (!card)
 		return;
+
+	PRINT_INFO("Removing lcs group device ....\n");
+	LCS_DBF_TEXT(3, setup, "remdev");
+	LCS_DBF_HEX(3, setup, &card, sizeof(void*));
 	if (ccwgdev->state == CCWGROUP_ONLINE) {
-		lcs_stop_device(card->dev); /* Ignore rc. */
-		sysfs_remove_link(&card->dev->class_dev.kobj,
-				  ccwgdev->dev.bus_id);
-		sysfs_remove_link(&ccwgdev->dev.kobj, card->dev->name);
-		unregister_netdev(card->dev);
+		lcs_shutdown_device(ccwgdev);
 	}
+	unregister_netdev(card->dev);
 	sysfs_remove_group(&ccwgdev->dev.kobj, &lcs_attr_group);
 	lcs_cleanup_card(card);
 	lcs_free_card(card);
diff -Nru a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h
--- a/drivers/s390/net/lcs.h	Sat Apr  3 19:38:54 2004
+++ b/drivers/s390/net/lcs.h	Sat Apr  3 19:38:54 2004
@@ -6,19 +6,36 @@
 #include <linux/workqueue.h>
 #include <asm/ccwdev.h>
 
-#define VERSION_LCS_H "$Revision: 1.13 $"
+#define VERSION_LCS_H "$Revision: 1.15 $"
 
 #define LCS_DBF_TEXT(level, name, text) \
 	do { \
 		debug_text_event(lcs_dbf_##name, level, text); \
 	} while (0)
 
+#define LCS_DBF_HEX(level,name,addr,len) \
+do { \
+	debug_event(lcs_dbf_##name,level,(void*)(addr),len); \
+} while (0)
+
+#define LCS_DBF_TEXT_(level,name,text...) \
+do {                                       \
+	sprintf(debug_buffer, text);  \
+		debug_text_event(lcs_dbf_##name,level, debug_buffer);\
+} while (0)
+
 /**
  * some more definitions for debug or output stuff
  */
 #define PRINTK_HEADER		" lcs: "
 
 /**
+ *	sysfs related stuff
+ */
+#define CARD_FROM_DEV(cdev) \
+	(struct lcs_card *) \
+	((struct ccwgroup_device *)cdev->dev.driver_data)->dev.driver_data;
+/**
  * CCW commands used in this driver
  */
 #define LCS_CCW_WRITE		0x01
@@ -123,6 +140,7 @@
 	CH_STATE_STOPPED,
 	CH_STATE_RUNNING,
 	CH_STATE_SUSPENDED,
+	CH_STATE_CLEARED,
 };
 
 /**
@@ -131,6 +149,7 @@
 enum lcs_dev_states {
 	DEV_STATE_DOWN,
 	DEV_STATE_UP,
+	DEV_STATE_RECOVER,
 };
 
 /**
diff -Nru a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
--- a/drivers/s390/net/netiucv.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/s390/net/netiucv.c	Sat Apr  3 19:38:44 2004
@@ -1,5 +1,5 @@
 /*
- * $Id: netiucv.c,v 1.38 2004/02/19 13:12:57 mschwide Exp $
+ * $Id: netiucv.c,v 1.47 2004/03/22 07:41:42 braunu Exp $
  *
  * IUCV network driver
  *
@@ -30,7 +30,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.38 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.47 $
  *
  */
 
@@ -229,6 +229,7 @@
 	"StartWait",
 	"StopWait",
 	"Running",
+	"StartRetry",
 };
 
 /**
@@ -251,6 +252,7 @@
 	"Stop",
 	"Connection up",
 	"Connection down",
+	"Timer",
 };
 
 /**
@@ -345,11 +347,6 @@
 	CONN_STATE_TX,
 
 	/**
-	 * Terminating
-	 */
-	CONN_STATE_TERM,
-
-	/**
 	 * Error during registration.
 	 */
 	CONN_STATE_REGERR,
@@ -495,7 +492,7 @@
 netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb)
 {
 	struct net_device     *dev = conn->netdev;
-	struct netiucv_priv   *privptr = (struct netiucv_priv *)dev->priv;
+	struct netiucv_priv   *privptr = dev->priv;
 	__u16          offset = 0;
 
 	skb_put(pskb, NETIUCV_HDRLEN);
@@ -767,7 +764,7 @@
 {
 	struct iucv_event *ev = (struct iucv_event *)arg;
 	struct iucv_connection *conn = ev->conn;
-
+	__u16 msglimit;
 	int rc;
 
 	pr_debug("%s() called\n", __FUNCTION__);
@@ -796,10 +793,11 @@
 
 	fsm_newstate(fi, CONN_STATE_SETUPWAIT);
 	rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic,
-			  conn->userid, iucv_host, 0, NULL, NULL, conn->handle,
+			  conn->userid, iucv_host, 0, NULL, &msglimit, conn->handle,
 			  conn);
 	switch (rc) {
 		case 0:
+			conn->netdev->tx_queue_len = msglimit;
 			return;
 		case 11:
 			printk(KERN_NOTICE
@@ -1214,7 +1212,7 @@
 static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	int          rc = 0;
-	struct netiucv_priv *privptr = (struct netiucv_priv *)dev->priv;
+	struct netiucv_priv *privptr = dev->priv;
 
 	/**
 	 * Some sanity checks ...
@@ -1290,7 +1288,6 @@
 /**
  * attributes in sysfs
  *****************************************************************************/
-#define CTRL_BUFSIZE 40
 
 static ssize_t
 user_show (struct device *dev, char *buf)
@@ -1300,7 +1297,57 @@
 	return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
 }
 
-static DEVICE_ATTR(user, 0444, user_show, NULL);
+static ssize_t
+user_write (struct device *dev, const char *buf, size_t count)
+{
+	struct netiucv_priv *priv = dev->driver_data;
+	struct net_device *ndev = priv->conn->netdev;
+	char    *p;
+	char    *tmp;
+	char 	username[10];
+	int 	i;
+
+	if (count>9) {
+		printk(KERN_WARNING
+			"netiucv: username too long (%d)!\n", (int)count);
+		return -EINVAL;
+	}
+
+	tmp = strsep((char **) &buf, "\n");
+	for (i=0, p=tmp; i<8 && *p; i++, p++) {
+		if (isalnum(*p) || (*p == '$'))
+			username[i]= *p;
+		else if (*p == '\n') {
+			/* trailing lf, grr */
+			break;
+		} else {
+			printk(KERN_WARNING
+				"netiucv: Invalid character in username!\n");
+			return -EINVAL;
+		}
+	}
+	while (i<9)
+		username[i++] = ' ';
+	username[9] = '\0';
+
+	if (memcmp(username, priv->conn->userid, 8) != 0) {
+		/* username changed */
+		if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
+			printk(KERN_WARNING
+				"netiucv: device %s active, connected to %s\n",
+				dev->bus_id, priv->conn->userid);
+			printk(KERN_WARNING
+				"netiucv: user cannot be updated\n");
+			return -EBUSY;
+		}
+	}
+	memcpy(priv->conn->userid, username, 9);
+
+	return count;
+
+}
+
+static DEVICE_ATTR(user, 0644, user_show, user_write);
 
 static ssize_t
 buffer_show (struct device *dev, char *buf)
@@ -1317,26 +1364,30 @@
 	struct net_device *ndev = priv->conn->netdev;
 	char         *e;
 	int          bs1;
-	char         tmp[CTRL_BUFSIZE];
 
 	if (count >= 39)
 		return -EINVAL;
 
-	if (copy_from_user(tmp, buf, count))
-		 return -EFAULT;
-	tmp[count+1] = '\0';
-	bs1 = simple_strtoul(tmp, &e, 0);
+	bs1 = simple_strtoul(buf, &e, 0);
+
+	if (e && (!isspace(*e))) {
+		printk(KERN_WARNING
+			"netiucv: Invalid character in buffer!\n");
+		return -EINVAL;
+	}
+	if (bs1 > NETIUCV_BUFSIZE_MAX) {
+		printk(KERN_WARNING
+			"netiucv: Given buffer size %d too large.\n",
+			bs1);
 
-	if ((bs1 > NETIUCV_BUFSIZE_MAX) ||
-	    (e && (!isspace(*e))))
 		return -EINVAL;
+	}
 	if ((ndev->flags & IFF_RUNNING) &&
 	    (bs1 < (ndev->mtu + NETIUCV_HDRLEN + 2)))
 		return -EINVAL;
 	if (bs1 < (576 + NETIUCV_HDRLEN + NETIUCV_HDRLEN))
 		return -EINVAL;
 
-
 	priv->conn->max_buffsize = bs1;
 	if (!(ndev->flags & IFF_RUNNING))
 		ndev->mtu = bs1 - NETIUCV_HDRLEN - NETIUCV_HDRLEN;
@@ -1606,20 +1657,10 @@
 	ret = netiucv_add_files(dev);
 	if (ret)
 		goto out_unreg;
-	ret = sysfs_create_link(&dev->kobj, &ndev->class_dev.kobj, ndev->name);
-	if (ret) 
-		goto out_rm_files;
-	ret = sysfs_create_link(&ndev->class_dev.kobj, &dev->kobj, dev->bus_id);
-	if (ret)
-		goto out_rm_link;
 	dev->driver_data = priv;
 	priv->dev = dev;
 	return 0;
 
-out_rm_link:
-	sysfs_remove_link(&dev->kobj, ndev->name);
-out_rm_files:
-	netiucv_remove_files(dev);
 out_unreg:
 	device_unregister(dev);
 	return ret;
@@ -1628,12 +1669,7 @@
 static void
 netiucv_unregister_device(struct device *dev)
 {
-	struct netiucv_priv *priv = dev->driver_data;
-	struct net_device *ndev = priv->conn->netdev;
-
 	pr_debug("%s() called\n", __FUNCTION__);
-	sysfs_remove_link(&ndev->class_dev.kobj, dev->bus_id);
-	sysfs_remove_link(&dev->kobj, ndev->name);
 	netiucv_remove_files(dev);
 	device_unregister(dev);
 }
@@ -1814,7 +1850,7 @@
 {
 	char *p;
 	char username[10];
-	int i;
+	int i, ret;
 	struct net_device *dev;
 
 	if (count>9) {
@@ -1846,30 +1882,37 @@
 		return -ENODEV;
 	}
 	
-	if (register_netdev(dev)) {
-		printk(KERN_WARNING
-		       "netiucv: Could not register '%s'\n", dev->name);
-		netiucv_free_netdevice(dev);
-		return -ENODEV;
+	if ((ret = netiucv_register_device(dev, ifno)))
+		goto out_free_ndev;
+	/* sysfs magic */
+	SET_NETDEV_DEV(dev, (struct device*)((struct netiucv_priv*)dev->priv)->dev);
+	if ((ret = register_netdev(dev))) {
+		netiucv_unregister_device((struct device*)((struct netiucv_priv*)dev->priv)->dev);
+		goto out_free_ndev;
 	}
 	printk(KERN_INFO "%s: '%s'\n", dev->name, netiucv_printname(username));
-	netiucv_register_device(dev, ifno);
 	ifno++;
 	
 	return count;
+
+out_free_ndev:
+	printk(KERN_WARNING
+		       "netiucv: Could not register '%s'\n", dev->name);
+	netiucv_free_netdevice(dev);
+	return ret;
 }
 
 DRIVER_ATTR(connection, 0200, NULL, conn_write);
 
 static struct device_driver netiucv_driver = {
-	.name = "NETIUCV",
+	.name = "netiucv",
 	.bus  = &iucv_bus,
 };
 
 static void
 netiucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.38 $";
+	char vbuf[] = "$Revision: 1.47 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
diff -Nru a/drivers/s390/net/qeth.c b/drivers/s390/net/qeth.c
--- a/drivers/s390/net/qeth.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/s390/net/qeth.c	Sat Apr  3 19:38:57 2004
@@ -755,7 +755,7 @@
 	int problem = 0;
 	struct qeth_card *card;
 
-	card = cdev->dev.driver_data;
+	card = CARD_FROM_CDEV(cdev);
 
 	if (atomic_read(&card->shutdown_phase))
 		return 0;
@@ -5930,7 +5930,7 @@
 			LOW_WATERMARK_PACK);
 	/* first_element is the last buffer that we got back from hydra */
 	if (!switch_state && !last_pci_hit)
-		return;;
+		return;
 	QETH_DBF_CARD3(0, trace, "stchcw", card);
 	if (atomic_swap(&card->outbound_ringbuffer_lock[queue], QETH_LOCK_FLUSH)
 	    == QETH_LOCK_UNLOCKED) {
@@ -6105,7 +6105,7 @@
 	sprintf(dbf_text, "%4x", rqparam);
 	QETH_DBF_TEXT4(0, trace, dbf_text);
 
-	card = cdev->dev.driver_data;
+	card = CARD_FROM_CDEV(cdev);
 	if (!card)
 		return;
 
@@ -6231,7 +6231,7 @@
 	sprintf(dbf_text, "%4x", rqparam);
 	QETH_DBF_TEXT4(0, trace, dbf_text);
 
-	card = cdev->dev.driver_data;
+	card = CARD_FROM_CDEV(cdev);
 	if (!card)
 		return;
 
@@ -6343,7 +6343,7 @@
 	sprintf(dbf_text, "%4x", rqparam);
 	QETH_DBF_TEXT4(0, trace, dbf_text);
 
-	card = cdev->dev.driver_data;
+	card = CARD_FROM_CDEV(cdev);
 	if (!card)
 		return;
 
@@ -6404,6 +6404,8 @@
 
 	QETH_DBF_CARD3(0, trace, "rgnd", card);
 
+	/* sysfs magic */
+	SET_NETDEV_DEV(card->dev, &card->gdev->dev);
 	result = register_netdev(card->dev);
 
 	return result;
@@ -6681,10 +6683,6 @@
 						   hard_start_xmit */
 
 	if (atomic_read(&card->is_registered)) {
-		/* Remove sysfs symlinks. */
-		sysfs_remove_link(&card->gdev->dev.kobj, card->dev_name);
-		sysfs_remove_link(&card->dev->class_dev.kobj,
-				  CARD_BUS_ID(card));
 		QETH_DBF_TEXT2(0, trace, "unregdev");
 		qeth_unregister_netdev(card);
 		qeth_wait_nonbusy(QETH_REMOVE_WAIT_TIME);
@@ -6885,7 +6883,7 @@
 
 	card->portname_required =
 	    ((!QETH_IDX_NO_PORTNAME_REQUIRED(card->dma_stuff->recbuf)) &&
-	     (card->type == QETH_CARD_TYPE_OSAE));;
+	     (card->type == QETH_CARD_TYPE_OSAE));
 
 	/*
 	 * however, as the portname indication of OSA is wrong, we have to
@@ -10622,13 +10620,10 @@
 	card->gdev = gdev;
 
 	gdev->cdev[0]->handler = qeth_interrupt_handler_read;
-	gdev->cdev[0]->dev.driver_data = card;
 
 	gdev->cdev[1]->handler = qeth_interrupt_handler_write;
-	gdev->cdev[1]->dev.driver_data = card;
 
 	gdev->cdev[2]->handler = qeth_interrupt_handler_qdio;
-	gdev->cdev[2]->dev.driver_data = card;
 
 	ret = __qeth_create_attributes(&gdev->dev);
 	if (ret != 0)
@@ -10694,17 +10689,6 @@
 	if (qeth_init_netdev(card))
 		goto out_remove;
 
-	if (sysfs_create_link(&card->gdev->dev.kobj, &card->dev->class_dev.kobj,
-			      card->dev_name)) {
-		qeth_unregister_netdev(card);
-		goto out_remove;
-	}
-	if (sysfs_create_link(&card->dev->class_dev.kobj, &card->gdev->dev.kobj,
-			      CARD_BUS_ID(card))) {
-		sysfs_remove_link(&card->gdev->dev.kobj, card->dev_name);
-		qeth_unregister_netdev(card);
-		goto out_remove;
-	}
 	return 0;		/* success */
 
 out_remove:
diff -Nru a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
--- a/drivers/s390/net/qeth.h	Sat Apr  3 19:38:40 2004
+++ b/drivers/s390/net/qeth.h	Sat Apr  3 19:38:40 2004
@@ -696,6 +696,8 @@
 #define CARD_RDEV_ID(card) card->gdev->cdev[0]->dev.bus_id
 #define CARD_WDEV_ID(card) card->gdev->cdev[1]->dev.bus_id
 #define CARD_DDEV_ID(card) card->gdev->cdev[2]->dev.bus_id
+#define CARD_FROM_CDEV(cdev) (struct qeth_card *) \
+	((struct ccwgroup_device *) cdev->dev.driver_data)->dev.driver_data
 
 #define SENSE_COMMAND_REJECT_BYTE 0
 #define SENSE_COMMAND_REJECT_FLAG 0x80
diff -Nru a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
--- a/drivers/s390/scsi/zfcp_erp.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/s390/scsi/zfcp_erp.c	Sat Apr  3 19:38:41 2004
@@ -2706,7 +2706,7 @@
 		ZFCP_LOG_INFO("error: Exchange of configuration data between "
 			      "the adapter %s and the device driver failed.\n",
 			      zfcp_get_busid_by_adapter(adapter));
-		retval = ZFCP_ERP_FAILED;;
+		retval = ZFCP_ERP_FAILED;
 	}
 
 	return retval;
diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
--- a/drivers/scsi/53c700.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/53c700.c	Sat Apr  3 19:38:41 2004
@@ -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 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 @@
 	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 @@
 
 	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 @@
 	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 @@
 	 * 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 @@
 		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 @@
 	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 @@
 				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 @@
 			//   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_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 @@
 			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 @@
 	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 @@
 	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 @@
 		/* 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 @@
 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 -Nru a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
--- a/drivers/scsi/53c700.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/53c700.h	Sat Apr  3 19:38:41 2004
@@ -99,19 +99,9 @@
 #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 @@
 	__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;
@@ -438,6 +429,7 @@
 		       #symbol, A_##symbol##_used[i], val)); \
 	} \
 }
+
 
 static inline __u8
 NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg)
diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
--- a/drivers/scsi/BusLogic.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/BusLogic.c	Sat Apr  3 19:38:56 2004
@@ -140,7 +140,7 @@
   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 -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
--- a/drivers/scsi/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/drivers/scsi/Kconfig	Sat Apr  3 19:38:55 2004
@@ -196,6 +196,25 @@
 	  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
@@ -424,7 +443,7 @@
 
 config SCSI_SATA_SIL
 	tristate "Silicon Image SATA support"
-	depends on SCSI_SATA && PCI && BROKEN
+	depends on SCSI_SATA && PCI && EXPERIMENTAL
 	help
 	  This option enables support for Silicon Image Serial ATA.
 
@@ -438,6 +457,14 @@
 
 	  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_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 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_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 -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile
--- a/drivers/scsi/Makefile	Sat Apr  3 19:38:55 2004
+++ b/drivers/scsi/Makefile	Sat Apr  3 19:38:55 2004
@@ -22,6 +22,14 @@
 
 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_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_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_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-$(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 -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
--- a/drivers/scsi/aacraid/linit.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/aacraid/linit.c	Sat Apr  3 19:38:42 2004
@@ -99,8 +99,8 @@
 
 	{ 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 @@
 	{ 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 @@
 
 	{ 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 @@
 	{ 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 -Nru a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
--- a/drivers/scsi/aacraid/rkt.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/scsi/aacraid/rkt.c	Sat Apr  3 19:38:55 2004
@@ -427,6 +427,7 @@
 	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 -Nru a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
--- a/drivers/scsi/aacraid/rx.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/scsi/aacraid/rx.c	Sat Apr  3 19:38:57 2004
@@ -427,6 +427,7 @@
 	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 -Nru a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
--- a/drivers/scsi/aacraid/sa.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/scsi/aacraid/sa.c	Sat Apr  3 19:38:44 2004
@@ -407,6 +407,7 @@
 	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 -Nru a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx	Sat Apr  3 19:38:43 2004
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
--- a/drivers/scsi/aic7xxx/aic7770.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/aic7xxx/aic7770.c	Sat Apr  3 19:38:56 2004
@@ -64,7 +64,7 @@
 static int aic7770_resume(struct ahc_softc *ahc);
 static int aha2840_load_seeprom(struct ahc_softc *ahc);
 static ahc_device_setup_t ahc_aic7770_VL_setup;
-static ahc_device_setup_t ahc_aic7770_EISA_setup;;
+static ahc_device_setup_t ahc_aic7770_EISA_setup;
 static ahc_device_setup_t ahc_aic7770_setup;
 
 struct aic7770_identity aic7770_ident_table[] =
diff -Nru a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
--- a/drivers/scsi/ata_piix.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/scsi/ata_piix.c	Sat Apr  3 19:38:43 2004
@@ -16,7 +16,7 @@
     May be copied or modified under the terms of the GNU General Public License
 
  */
-#include <linux/config.h>
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -125,7 +125,6 @@
 	.exec_command		= ata_exec_command_pio,
 
 	.phy_reset		= piix_pata_phy_reset,
-	.phy_config		= pata_phy_config,
 
 	.bmdma_start		= ata_bmdma_start_pio,
 	.fill_sg		= ata_fill_sg,
@@ -148,7 +147,6 @@
 	.exec_command		= ata_exec_command_pio,
 
 	.phy_reset		= piix_sata_phy_reset,
-	.phy_config		= pata_phy_config,	/* not a typo */
 
 	.bmdma_start		= ata_bmdma_start_pio,
 	.fill_sg		= ata_fill_sg,
diff -Nru a/drivers/scsi/constants.c b/drivers/scsi/constants.c
--- a/drivers/scsi/constants.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/scsi/constants.c	Sat Apr  3 19:38:54 2004
@@ -1135,7 +1135,7 @@
 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 -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
--- a/drivers/scsi/cpqfcTSinit.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/cpqfcTSinit.c	Sat Apr  3 19:38:41 2004
@@ -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>
@@ -220,7 +216,7 @@
   cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;  
   cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;  
   cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
-  cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;;  
+  cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;
   cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
   cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
 
diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
--- a/drivers/scsi/dc395x.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/dc395x.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 #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 @@
 #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 @@
 	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 @@
 	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 @@
 	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 @@
 	u8 init_tcq_flag;
 };
 
-/*-----------------------------------------------------------------------
-  Adapter Control Block
-  -----------------------------------------------------------------------*/
 struct AdapterCtlBlk {
 	struct Scsi_Host *scsi_host;
 
@@ -423,80 +331,63 @@
 };
 
 
-
-
 /*---------------------------------------------------------------------------
                             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 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 @@
 	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 @@
 /* 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 @@
 
 
 /*
- * 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 @@
  * 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 @@
  * 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 @@
  * 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 @@
  *
  * @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 @@
  *
  * @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 @@
 /*---------------------------------------------------------------------------
  ---------------------------------------------------------------------------*/
 
-/**
- * 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 @@
 }
 
 
-/*
- * 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 @@
 
 
 /* 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 @@
 }
 
 
-/*
- * 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 @@
 }
 
 
-/*
- * 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 @@
 }
 
 
-/*
- * 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 @@
 
 
 /* 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 @@
 	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 @@
 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 @@
 
 
 /* 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 @@
 		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 @@
 	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 @@
  *        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 @@
 
 	/* 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 @@
 	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 @@
 	cmd->scsi_done = done;
 	cmd->result = 0;
 
-	/* get a free SRB */
 	srb = srb_get_free(acb);
 	if (!srb)
 	{
@@ -1411,11 +1135,10 @@
 		 * 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 @@
 		/* 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 @@
 	 * 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 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 @@
 }
 
 
-/*
- * 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 @@
 	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 @@
 	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 @@
 
 
 /*
- *********************************************************************
- * 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 @@
 	 */
 	/* 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 @@
 		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 @@
 	*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 @@
 	*ptr++ = wide;
 	srb->msg_count += 4;
 	srb->state |= SRB_DO_WIDE_NEGO;
-	TRACEPRINTF("W *");
 }
 
 
@@ -1809,7 +1472,7 @@
 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 @@
 	}
 	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 @@
 		 * 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 @@
 		}
 		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 @@
 			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 @@
 			      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 @@
 		 * 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 @@
 		/* 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 @@
  * @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 @@
 		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 @@
 			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 @@
 		/* 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 @@
 		/* 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 @@
 	}
 	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 @@
 		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 @@
 	/* 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 @@
  * 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_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++) {
+	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;
+	}
+
+	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 @@
  * 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 @@
  * 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 @@
 	 * 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 @@
 			 * 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 @@
 		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 @@
 		 * 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 @@
 			    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 @@
 			}
 		}
 	}
-#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 @@
 	 */
 	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 @@
 #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 @@
 				       "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 @@
 			 * 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 @@
 			 */
 		}
 #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 @@
 				       "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 @@
 			 * 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");
-		}
-	}
-#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
-	 */
+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);
-	TRACEPRINTF(".*");
 }
 
 
-/*
- ********************************************************************
- * scsiio
- *		data_out_phase1
- *		data_in_phase1
- ********************************************************************
- */
-static
-void data_io_transfer(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
-		      u16 io_dir)
+static void data_io_transfer(struct AdapterCtlBlk *acb, 
+		struct ScsiReqBlk *srb, u16 io_dir)
 {
+	struct DeviceCtlBlk *dcb = srb->dcb;
 	u8 bval;
-	struct DeviceCtlBlk *dcb;
-
-	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);
-			}
+	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);
+		}
+
+	}
 #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 (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);
-				}
-				/*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */
+	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("\n");
-				DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
-						  SCMD_FIFO_OUT);
-			}
-		}
-#endif				/* DC395x_LASTPIO */
-		else {		/* xfer pad */
+					printk(" %02x", (unsigned char) *(srb->virt_addr));
 
-			u8 data = 0, data2 = 0;
-			if (srb->sg_count) {
-				srb->adapter_status = H_OVER_UNDER_RUN;
-				srb->status |= OVER_RUN;
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 
+				     *(srb->virt_addr)++);
+
+				sg_subtract_one(srb);
 			}
-			/*
-			 * 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');
+			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);
+			}
+			/*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) {
+				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 @@
 
 
 /* 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 @@
 	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 @@
 	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 @@
 	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 @@
 
 
 /* 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 @@
 	    && !(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 @@
 		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 @@
 		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 @@
 		    && !(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 @@
 }
 
 
-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 @@
 	    && !(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 @@
 	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 @@
  *	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 @@
 		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 @@
 			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 @@
 				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 @@
 				/*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 @@
 }
 
 
-/*
- ********************************************************************
- * 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 @@
 			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 @@
 				}
 				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 @@
 			/*
 			 * 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 @@
 			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 @@
 	}
 	/* 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 @@
 				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 inline u8 tagq_blacklist(char *name)
 {
 #ifndef DC395x_NO_TAGQ
@@ -4038,8 +3215,7 @@
 }
 
 
-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 @@
 		    /*(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 @@
 }
 
 
-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 @@
 }
 
 
-/* 
- ********************************************************************
- * 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 @@
 
 
 /*
- ********************************************************************
- * 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 @@
 		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 @@
 			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 @@
 
 	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 @@
 	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 @@
 			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 @@
 		}
 		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 @@
 			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 @@
 			}
 		}
 		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 @@
 	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 @@
 }
 
 
-/*
- ********************************************************************
- * 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 @@
 	    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 @@
 		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 @@
 	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 @@
  *
  * 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 @@
 		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 @@
  * @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 @@
  * @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 @@
  * @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 @@
  *
  * @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 @@
  *
  * @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 @@
  *
  * @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 @@
  *
  * @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 @@
  * @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 @@
  * @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 @@
  * @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 @@
 	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 @@
  *
  * 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 @@
  * @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 @@
 	     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 @@
  * @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 @@
 	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 @@
 		 * 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 @@
 		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 @@
 }
 
 
-
-
 /**
  * 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);
+		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);
-}
-
-
-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 @@
 
 	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 @@
  *
  * @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 @@
  *
  * @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 @@
  *
  * @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 @@
  * 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 @@
 		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 @@
 	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 @@
  *
  * @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 @@
  *
  * @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 @@
 		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 @@
  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 @@
 				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 @@
 }
 
 
-
-
-/*
- * SCSI host template
- */
 static Scsi_Host_Template dc395x_driver_template = {
 	.module                 = THIS_MODULE,
 	.proc_name              = DC395X_NAME,
@@ -5799,8 +4762,7 @@
  * 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 @@
  *
  * 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 @@
 
 	/* 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 @@
 	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 @@
 	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 @@
 }
 
 
-/*
- * 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 @@
 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 @@
  *
  * 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 @@
 /**
  * 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 -Nru a/drivers/scsi/dc395x.h b/drivers/scsi/dc395x.h
--- a/drivers/scsi/dc395x.h	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/dc395x.h	Sat Apr  3 19:38:56 2004
@@ -7,18 +7,8 @@
 /*	(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"
 
 /************************************************************************/
 /*									*/
diff -Nru a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
--- a/drivers/scsi/dec_esp.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/scsi/dec_esp.c	Sat Apr  3 19:38:54 2004
@@ -378,7 +378,7 @@
 
 static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd * sp)
 {
-	return sp->SCp.this_residual;;
+	return sp->SCp.this_residual;
 }
 
 static void dma_dump_state(struct NCR_ESP *esp)
diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
--- a/drivers/scsi/dpt_i2o.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/scsi/dpt_i2o.c	Sat Apr  3 19:38:55 2004
@@ -2161,7 +2161,7 @@
 	(adpt_hba*)(host->hostdata[0]) = pHba;
 	pHba->host = host;
 
-	host->irq = pHba->pDev->irq;;
+	host->irq = pHba->pDev->irq;
 	/* no IO ports, so don't have to set host->io_port and 
 	 * host->n_io_port
 	 */
diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c
--- a/drivers/scsi/eata.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/scsi/eata.c	Sat Apr  3 19:38:55 2004
@@ -1598,17 +1598,17 @@
    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 -Nru a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
--- a/drivers/scsi/gdth.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/scsi/gdth.c	Sat Apr  3 19:38:44 2004
@@ -1358,7 +1358,7 @@
         
         /* disable board interrupts, deinit services */
         gdth_writeb(0xff, &dp6_ptr->io.irqdel);
-        gdth_writeb(0x00, &dp6_ptr->io.irqen);;
+        gdth_writeb(0x00, &dp6_ptr->io.irqen);
         gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status);
         gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
 
diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/hosts.c	Sat Apr  3 19:38:41 2004
@@ -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"
@@ -221,6 +222,11 @@
 	shost->max_channel = 0;
 	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
diff -Nru a/drivers/scsi/i91uscsi.c b/drivers/scsi/i91uscsi.c
--- a/drivers/scsi/i91uscsi.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/i91uscsi.c	Sat Apr  3 19:38:41 2004
@@ -2133,7 +2133,7 @@
 		tul_append_done_scb(pCurHcb, pCurScb);
 	}
 	for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
-		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);;
+		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
 	}
 	return (-1);
 }
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/scsi/ide-scsi.c	Sat Apr  3 19:38:45 2004
@@ -78,6 +78,7 @@
 #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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 				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 @@
 	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 @@
 	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 @@
 		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 @@
 	.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 @@
 	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;
 	}
-	return FAILED;
+
+	/* 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;
+	}
+
+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 @@
 	.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,
@@ -967,7 +1100,16 @@
 		return 1;
 
 	host->max_id = 1;
-	host->max_lun = 1;
+
+#if IDESCSI_DEBUG_LOG
+	if (drive->id->last_lun)
+		printk(KERN_NOTICE "%s: id->last_lun=%u\n", drive->name, drive->id->last_lun);
+#endif
+	if ((drive->id->last_lun & 0x7) != 7)
+		host->max_lun = (drive->id->last_lun & 0x7) + 1;
+	else
+		host->max_lun = 1;
+
 	drive->driver_data = host;
 	idescsi = scsihost_to_idescsi(host);
 	idescsi->drive = drive;
diff -Nru a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
--- a/drivers/scsi/in2000.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/scsi/in2000.c	Sat Apr  3 19:38:54 2004
@@ -2288,7 +2288,7 @@
 		return 0;	/* return 0 to signal end-of-file */
 	}
 	if (off > 0x40000)	/* ALWAYS stop after 256k bytes have been read */
-		stop = 1;;
+		stop = 1;
 	if (hd->proc & PR_STOP)	/* stop every other time */
 		stop = 1;
 	return strlen(bp);
diff -Nru a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c
--- a/drivers/scsi/ini9100u.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/ini9100u.c	Sat Apr  3 19:38:42 2004
@@ -180,15 +180,6 @@
 
 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 @@
 	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 -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
--- a/drivers/scsi/libata-core.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/scsi/libata-core.c	Sat Apr  3 19:38:40 2004
@@ -49,13 +49,16 @@
 				    unsigned long tmout_pat,
 			    	    unsigned long tmout);
 static void __ata_dev_select (struct ata_port *ap, unsigned int device);
+#if 0 /* to be used eventually */
 static void ata_qc_push (struct ata_queued_cmd *qc, unsigned int append);
+#endif
 static void ata_dma_complete(struct ata_port *ap, u8 host_stat,
 			     unsigned int done_late);
 static void ata_host_set_pio(struct ata_port *ap);
 static void ata_host_set_udma(struct ata_port *ap);
 static void ata_dev_set_pio(struct ata_port *ap, unsigned int device);
 static void ata_dev_set_udma(struct ata_port *ap, unsigned int device);
+static void ata_set_mode(struct ata_port *ap);
 
 static unsigned int ata_unique_id = 1;
 
@@ -141,7 +144,7 @@
 	}
 
 	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 +158,7 @@
 	}
 
 	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 +202,7 @@
 	}
 
 	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 +216,7 @@
 	}
 
 	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 +253,7 @@
 {
 	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 +274,7 @@
 {
 	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 +420,7 @@
  */
 u8 ata_check_status_pio(struct ata_port *ap)
 {
-	return inb(ap->ioaddr.cmdstat_addr);
+	return inb(ap->ioaddr.status_addr);
 }
 
 /**
@@ -433,7 +436,7 @@
  */
 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[] = {
@@ -1029,7 +1032,7 @@
 	if ((!found) || (ap->flags & ATA_FLAG_PORT_DISABLED))
 		goto err_out_disable;
 
-	ap->ops->phy_config(ap);
+	ata_set_mode(ap);
 	if (ap->flags & ATA_FLAG_PORT_DISABLED)
 		goto err_out_disable;
 
@@ -1118,13 +1121,13 @@
 }
 
 /**
- *	pata_phy_config -
- *	@ap:
+ *	ata_set_mode - Program timings and issue SET FEATURES - XFER
+ *	@ap: port on which timings will be programmed
  *
  *	LOCKING:
  *
  */
-void pata_phy_config(struct ata_port *ap)
+static void ata_set_mode(struct ata_port *ap)
 {
 	unsigned int force_pio;
 
@@ -1156,6 +1159,8 @@
 			return;
 	}
 
+	if (ap->ops->post_set_mode)
+		ap->ops->post_set_mode(ap);
 }
 
 /**
@@ -1346,12 +1351,6 @@
 
 	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 +1371,14 @@
 	/* 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 +1404,14 @@
 	    (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 +1458,8 @@
 		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 +1523,9 @@
 	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;
@@ -1960,6 +1976,7 @@
 	kunmap(sg[qc->cursg].page);
 }
 
+#if 0 /* to be used eventually */
 /**
  *	ata_eng_schedule - run an iteration of the pio/dma/whatever engine
  *	@ap: port on which activity will occur
@@ -1972,6 +1989,7 @@
 {
 	/* FIXME */
 }
+#endif
 
 /**
  *	ata_eng_timeout - Handle timeout of queued command
@@ -2161,6 +2179,7 @@
 		clear_bit(tag, &ap->qactive);
 }
 
+#if 0 /* to be used eventually */
 /**
  *	ata_qc_push -
  *	@qc:
@@ -2182,6 +2201,7 @@
 	if (!test_and_set_bit(ATA_EFLG_ACTIVE, &eng->flags))
 		ata_eng_schedule(ap, eng);
 }
+#endif
 
 /**
  *	ata_qc_issue -
@@ -2246,9 +2266,12 @@
 	mb();	/* make sure PRD table writes are visible to controller */
 	writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
 
-	/* specify data direction */
-	/* FIXME: redundant to later start-dma command? */
-	writeb(rw ? 0 : ATA_DMA_WR, mmio + ATA_DMA_CMD);
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = readb(mmio + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	writeb(dmactl, mmio + ATA_DMA_CMD);
 
 	/* clear interrupt, error bits */
 	host_stat = readb(mmio + ATA_DMA_STATUS);
@@ -2258,7 +2281,6 @@
 	ap->ops->exec_command(ap, &qc->tf);
 
 	/* start host DMA transaction */
-	dmactl = readb(mmio + ATA_DMA_CMD);
 	writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
 
 	/* Strictly, one may wish to issue a readb() here, to
@@ -2291,9 +2313,12 @@
 	/* load PRD table addr. */
 	outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
 
-	/* specify data direction */
-	/* FIXME: redundant to later start-dma command? */
-	outb(rw ? 0 : ATA_DMA_WR, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 
 	/* clear interrupt, error bits */
 	host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
@@ -2304,7 +2329,6 @@
 	ap->ops->exec_command(ap, &qc->tf);
 
 	/* start host DMA transaction */
-	dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 	outb(dmactl | ATA_DMA_START,
 	     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 }
@@ -2327,14 +2351,16 @@
 		void *mmio = (void *) ap->ioaddr.bmdma_addr;
 
 		/* clear start/stop bit */
-		writeb(0, mmio + ATA_DMA_CMD);
+		writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+		       mmio + ATA_DMA_CMD);
 
 		/* ack intr, err bits */
 		writeb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
 		       mmio + ATA_DMA_STATUS);
 	} else {
 		/* clear start/stop bit */
-		outb(0, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+		outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+		     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 
 		/* ack intr, err bits */
 		outb(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
@@ -2369,8 +2395,8 @@
  *	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 +2754,7 @@
 	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 +3052,14 @@
 {
 	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;
 }
 
 /**
@@ -3121,6 +3149,9 @@
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
 		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
 
 	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
 	if (!probe_ent) {
@@ -3153,12 +3184,14 @@
 
 	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 +3206,13 @@
 	} 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;
@@ -3358,7 +3393,6 @@
 EXPORT_SYMBOL_GPL(ata_bmdma_start_mmio);
 EXPORT_SYMBOL_GPL(ata_port_probe);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
-EXPORT_SYMBOL_GPL(pata_phy_config);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
 EXPORT_SYMBOL_GPL(ata_port_disable);
 EXPORT_SYMBOL_GPL(ata_pci_init_one);
@@ -3367,4 +3401,4 @@
 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 -Nru a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
--- a/drivers/scsi/libata-scsi.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/scsi/libata-scsi.c	Sat Apr  3 19:38:43 2004
@@ -251,6 +251,8 @@
 		tf->lbam = scsicmd[2];
 		tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */
 
+		tf->device |= ATA_LBA;
+
 		VPRINTK("six-byte command\n");
 		return 0;
 	}
diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h
--- a/drivers/scsi/libata.h	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/libata.h	Sat Apr  3 19:38:41 2004
@@ -26,7 +26,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME	"libata"
-#define DRV_VERSION	"1.01"	/* must be exactly four chars */
+#define DRV_VERSION	"1.02"	/* must be exactly four chars */
 
 struct ata_scsi_args {
 	struct ata_port		*ap;
diff -Nru a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
--- a/drivers/scsi/mac53c94.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/mac53c94.c	Sat Apr  3 19:38:41 2004
@@ -25,8 +25,11 @@
 #include <asm/pci-bridge.h>
 #include <asm/macio.h>
 
-#include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
 #include "mac53c94.h"
 
 enum fsc_phase {
@@ -44,9 +47,9 @@
 	int	dmaintr;
 	int	clk_freq;
 	struct	Scsi_Host *host;
-	Scsi_Cmnd *request_q;
-	Scsi_Cmnd *request_qtail;
-	Scsi_Cmnd *current_req;		/* req we're currently working on */
+	struct scsi_cmnd *request_q;
+	struct scsi_cmnd *request_qtail;
+	struct scsi_cmnd *current_req;		/* req we're currently working on */
 	enum fsc_phase phase;		/* what we're currently trying to do */
 	struct dbdma_cmd *dma_cmds;	/* space for dbdma commands, aligned */
 	void	*dma_cmd_space;
@@ -60,15 +63,15 @@
 static void mac53c94_interrupt(int, void *, struct pt_regs *);
 static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *);
 static void cmd_done(struct fsc_state *, int result);
-static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
+static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
 
 
-static int mac53c94_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
 	struct fsc_state *state;
 
 #if 0
-	if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
+	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
 		int i;
 		printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd);
 		for (i = 0; i < cmd->cmd_len; ++i)
@@ -95,12 +98,12 @@
 	return 0;
 }
 
-static int mac53c94_abort(Scsi_Cmnd *cmd)
+static int mac53c94_abort(struct scsi_cmnd *cmd)
 {
-	return SCSI_ABORT_SNOOZE;
+	return FAILED;
 }
 
-static int mac53c94_host_reset(Scsi_Cmnd *cmd)
+static int mac53c94_host_reset(struct scsi_cmnd *cmd)
 {
 	struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata;
 	struct mac53c94_regs *regs = state->regs;
@@ -139,7 +142,7 @@
  */
 static void mac53c94_start(struct fsc_state *state)
 {
-	Scsi_Cmnd *cmd;
+	struct scsi_cmnd *cmd;
 	struct mac53c94_regs *regs = state->regs;
 	int i;
 
@@ -148,7 +151,7 @@
 	if (state->request_q == NULL)
 		return;
 	state->current_req = cmd = state->request_q;
-	state->request_q = (Scsi_Cmnd *) cmd->host_scribble;
+	state->request_q = (struct scsi_cmnd *) cmd->host_scribble;
 
 	/* Off we go */
 	writeb(0, &regs->count_lo);
@@ -190,10 +193,9 @@
 	struct fsc_state *state = (struct fsc_state *) dev_id;
 	struct mac53c94_regs *regs = state->regs;
 	struct dbdma_regs *dma = state->dma;
-	Scsi_Cmnd *cmd = state->current_req;
+	struct scsi_cmnd *cmd = state->current_req;
 	int nb, stat, seq, intr;
 	static int mac53c94_errors;
-	int dma_dir;
 
 	/*
 	 * Apparently, reading the interrupt register unlatches
@@ -308,14 +310,13 @@
 			printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
 		}
 		writel(RUN << 16, &dma->control);	/* stop dma */
-		dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 		if (cmd->use_sg != 0) {
 			pci_unmap_sg(state->pdev,
 				(struct scatterlist *)cmd->request_buffer,
-				cmd->use_sg, dma_dir);
+				cmd->use_sg, cmd->sc_data_direction);
 		} else {
 			pci_unmap_single(state->pdev, state->dma_addr,
-				cmd->request_bufflen, dma_dir);
+				cmd->request_bufflen, cmd->sc_data_direction);
 		}
 		/* should check dma status */
 		writeb(CMD_I_COMPLETE, &regs->command);
@@ -347,7 +348,7 @@
 
 static void cmd_done(struct fsc_state *state, int result)
 {
-	Scsi_Cmnd *cmd;
+	struct scsi_cmnd *cmd;
 
 	cmd = state->current_req;
 	if (cmd != 0) {
@@ -362,24 +363,24 @@
 /*
  * Set up DMA commands for transferring data.
  */
-static void set_dma_cmds(struct fsc_state *state, Scsi_Cmnd *cmd)
+static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd)
 {
 	int i, dma_cmd, total;
 	struct scatterlist *scl;
 	struct dbdma_cmd *dcmds;
 	dma_addr_t dma_addr;
 	u32 dma_len;
-	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
-	dma_cmd = cmd->sc_data_direction == SCSI_DATA_WRITE? OUTPUT_MORE:
-		INPUT_MORE;
+	dma_cmd = cmd->sc_data_direction == DMA_TO_DEVICE ?
+			OUTPUT_MORE : INPUT_MORE;
 	dcmds = state->dma_cmds;
 	if (cmd->use_sg > 0) {
 		int nseg;
 
 		total = 0;
 		scl = (struct scatterlist *) cmd->buffer;
-		nseg = pci_map_sg(state->pdev, scl, cmd->use_sg, dma_dir);
+		nseg = pci_map_sg(state->pdev, scl, cmd->use_sg,
+				cmd->sc_data_direction);
 		for (i = 0; i < nseg; ++i) {
 			dma_addr = sg_dma_address(scl);
 			dma_len = sg_dma_len(scl);
@@ -398,7 +399,7 @@
 		if (total > 0xffff)
 			panic("mac53c94: transfer size >= 64k");
 		dma_addr = pci_map_single(state->pdev, cmd->request_buffer,
-					  total, dma_dir);
+					  total, cmd->sc_data_direction);
 		state->dma_addr = dma_addr;
 		st_le16(&dcmds->req_count, total);
 		st_le32(&dcmds->phy_addr, dma_addr);
@@ -411,7 +412,7 @@
 	cmd->SCp.this_residual = total;
 }
 
-static Scsi_Host_Template mac53c94_template = {
+static struct scsi_host_template mac53c94_template = {
 	.proc_name	= "53c94",
 	.name		= "53C94",
 	.queuecommand	= mac53c94_queue,
diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
--- a/drivers/scsi/megaraid.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/scsi/megaraid.c	Sat Apr  3 19:38:40 2004
@@ -261,10 +261,6 @@
 			"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 @@
 	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 @@
 			*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 @@
 	 */
 	*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;
 }
@@ -4614,6 +4582,7 @@
 }
 
 static struct scsi_host_template megaraid_template = {
+	.module				= THIS_MODULE,
 	.name				= "MegaRAID",
 	.proc_name			= "megaraid",
 	.info				= megaraid_info,
@@ -5118,10 +5087,6 @@
 	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 +5094,13 @@
 				"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 -Nru a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
--- a/drivers/scsi/mesh.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/scsi/mesh.c	Sat Apr  3 19:38:45 2004
@@ -44,8 +44,11 @@
 #include <asm/pci-bridge.h>
 #include <asm/macio.h>
 
-#include "scsi.h"
-#include "hosts.h"
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
 #include "mesh.h"
 
 #if 1
@@ -131,7 +134,7 @@
 	enum sdtr_phase sdtr_state;
 	int	sync_params;
 	int	data_goes_out;		/* guess as to data direction */
-	Scsi_Cmnd *current_req;
+	struct scsi_cmnd *current_req;
 	u32	saved_ptr;
 #ifdef MESH_DBG
 	int	log_ix;
@@ -147,12 +150,12 @@
 	int	dmaintr;
 	struct	Scsi_Host *host;
 	struct	mesh_state *next;
-	Scsi_Cmnd *request_q;
-	Scsi_Cmnd *request_qtail;
+	struct scsi_cmnd *request_q;
+	struct scsi_cmnd *request_qtail;
 	enum mesh_phase phase;		/* what we're currently trying to do */
 	enum msg_phase msgphase;
 	int	conn_tgt;		/* target we're connected to */
-	Scsi_Cmnd *current_req;		/* req we're currently working on */
+	struct scsi_cmnd *current_req;		/* req we're currently working on */
 	int	data_ptr;
 	int	dma_started;
 	int	dma_count;
@@ -185,7 +188,7 @@
 static void mesh_done(struct mesh_state *ms, int start_next);
 static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs);
 static void cmd_complete(struct mesh_state *ms);
-static void set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd);
+static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
 static void halt_dma(struct mesh_state *ms);
 static void phase_mismatch(struct mesh_state *ms);
 
@@ -344,7 +347,7 @@
 /*
  * Complete a SCSI command
  */
-static void mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
+static void mesh_completed(struct mesh_state *ms, struct scsi_cmnd *cmd)
 {
 	(*cmd->scsi_done)(cmd);
 }
@@ -402,14 +405,14 @@
 }
 
 
-static void mesh_start_cmd(struct mesh_state *ms, Scsi_Cmnd *cmd)
+static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
 {
 	volatile struct mesh_regs *mr = ms->mesh;
 	int t, id;
 
 	id = cmd->device->id;
 	ms->current_req = cmd;
-	ms->tgts[id].data_goes_out = cmd->sc_data_direction == SCSI_DATA_WRITE;
+	ms->tgts[id].data_goes_out = cmd->sc_data_direction == DMA_TO_DEVICE;
 	ms->tgts[id].current_req = cmd;
 
 #if 1
@@ -558,7 +561,7 @@
  */
 static void mesh_start(struct mesh_state *ms)
 {
-	Scsi_Cmnd *cmd, *prev, *next;
+	struct scsi_cmnd *cmd, *prev, *next;
 
 	if (ms->phase != idle || ms->current_req != NULL) {
 		printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)",
@@ -568,14 +571,14 @@
 
 	while (ms->phase == idle) {
 		prev = NULL;
-		for (cmd = ms->request_q; ; cmd = (Scsi_Cmnd *) cmd->host_scribble) {
+		for (cmd = ms->request_q; ; cmd = (struct scsi_cmnd *) cmd->host_scribble) {
 			if (cmd == NULL)
 				return;
 			if (ms->tgts[cmd->device->id].current_req == NULL)
 				break;
 			prev = cmd;
 		}
-		next = (Scsi_Cmnd *) cmd->host_scribble;
+		next = (struct scsi_cmnd *) cmd->host_scribble;
 		if (prev == NULL)
 			ms->request_q = next;
 		else
@@ -589,7 +592,7 @@
 
 static void mesh_done(struct mesh_state *ms, int start_next)
 {
-	Scsi_Cmnd *cmd;
+	struct scsi_cmnd *cmd;
 	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
 
 	cmd = ms->current_req;
@@ -679,7 +682,7 @@
 	int i, seq, nb;
 	volatile struct mesh_regs *mr = ms->mesh;
 	volatile struct dbdma_regs *md = ms->dma;
-	Scsi_Cmnd *cmd = ms->current_req;
+	struct scsi_cmnd *cmd = ms->current_req;
 	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
 
 	dlog(ms, "start_phase nmo/exc/fc/seq = %.8x",
@@ -854,7 +857,7 @@
 static void reselected(struct mesh_state *ms)
 {
 	volatile struct mesh_regs *mr = ms->mesh;
-	Scsi_Cmnd *cmd;
+	struct scsi_cmnd *cmd;
 	struct mesh_target *tp;
 	int b, t, prev;
 
@@ -985,7 +988,7 @@
 {
 	int tgt;
 	struct mesh_target *tp;
-	Scsi_Cmnd *cmd;
+	struct scsi_cmnd *cmd;
 	volatile struct mesh_regs *mr = ms->mesh;
 
 	for (tgt = 0; tgt < 8; ++tgt) {
@@ -1000,7 +1003,7 @@
 	}
 	ms->current_req = NULL;
 	while ((cmd = ms->request_q) != NULL) {
-		ms->request_q = (Scsi_Cmnd *) cmd->host_scribble;
+		ms->request_q = (struct scsi_cmnd *) cmd->host_scribble;
 		cmd->result = DID_RESET << 16;
 		mesh_completed(ms, cmd);
 	}
@@ -1154,7 +1157,7 @@
 static void handle_msgin(struct mesh_state *ms)
 {
 	int i, code;
-	Scsi_Cmnd *cmd = ms->current_req;
+	struct scsi_cmnd *cmd = ms->current_req;
 	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
 
 	if (ms->n_msgin == 0)
@@ -1252,7 +1255,7 @@
 /*
  * Set up DMA commands for transferring data.
  */
-static void set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd)
+static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
 {
 	int i, dma_cmd, total, off, dtot;
 	struct scatterlist *scl;
@@ -1270,7 +1273,7 @@
 			scl = (struct scatterlist *) cmd->buffer;
 			off = ms->data_ptr;
 			nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
-				 scsi_to_pci_dma_dir(cmd ->sc_data_direction));
+					  cmd->sc_data_direction);
 			for (i = 0; i <nseg; ++i, ++scl) {
 				u32 dma_addr = sg_dma_address(scl);
 				u32 dma_len = sg_dma_len(scl);
@@ -1324,7 +1327,7 @@
 {
 	volatile struct dbdma_regs *md = ms->dma;
 	volatile struct mesh_regs *mr = ms->mesh;
-	Scsi_Cmnd *cmd = ms->current_req;
+	struct scsi_cmnd *cmd = ms->current_req;
 	int t, nb;
 
 	if (!ms->tgts[ms->conn_tgt].data_goes_out) {
@@ -1364,8 +1367,7 @@
 	if (cmd->use_sg != 0) {
 		struct scatterlist *sg;
 		sg = (struct scatterlist *)cmd->request_buffer;
-		pci_unmap_sg(ms->pdev, sg, cmd->use_sg,
-			     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+		pci_unmap_sg(ms->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
 	}
 	ms->dma_started = 0;
 }
@@ -1452,7 +1454,7 @@
 static void cmd_complete(struct mesh_state *ms)
 {
 	volatile struct mesh_regs *mr = ms->mesh;
-	Scsi_Cmnd *cmd = ms->current_req;
+	struct scsi_cmnd *cmd = ms->current_req;
 	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
 	int seq, n, t;
 
@@ -1635,7 +1637,7 @@
  * Called by midlayer with host locked to queue a new
  * request
  */
-static int mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
 {
 	struct mesh_state *ms;
 
@@ -1692,7 +1694,7 @@
  * queue if it isn't connected yet, and for pending command, assert
  * ATN until the bus gets freed.
  */
-static int mesh_abort(Scsi_Cmnd *cmd)
+static int mesh_abort(struct scsi_cmnd *cmd)
 {
 	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
 
@@ -1700,7 +1702,7 @@
 	mesh_dump_regs(ms);
 	dumplog(ms, cmd->device->id);
 	dumpslog(ms);
-	return SCSI_ABORT_SNOOZE;
+	return FAILED;
 }
 
 /*
@@ -1709,7 +1711,7 @@
  * The midlayer will wait for devices to come back, we don't need
  * to do that ourselves
  */
-static int mesh_host_reset(Scsi_Cmnd *cmd)
+static int mesh_host_reset(struct scsi_cmnd *cmd)
 {
 	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
 	volatile struct mesh_regs *mr = ms->mesh;
@@ -1832,7 +1834,7 @@
 	return 0;
 }
 
-static Scsi_Host_Template mesh_template = {
+static struct scsi_host_template mesh_template = {
 	.proc_name			= "mesh",
 	.name				= "MESH",
 	.queuecommand			= mesh_queue,
diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/ncr53c8xx.c	Sat Apr  3 19:38:42 2004
@@ -5140,9 +5140,10 @@
 		*/
 		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 -Nru a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
--- a/drivers/scsi/oktagon_esp.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/oktagon_esp.c	Sat Apr  3 19:38:41 2004
@@ -12,7 +12,6 @@
 #define USE_BOTTOM_HALF
 #endif
 
-#define __KERNEL_SYSCALLS__
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -42,8 +41,6 @@
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #endif
-
-#include <linux/unistd.h>
 
 /* The controller registers can be found in the Z2 config area at these
  * offsets:
diff -Nru a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
--- a/drivers/scsi/pci2000.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/scsi/pci2000.c	Sat Apr  3 19:38:45 2004
@@ -320,7 +320,7 @@
 
 	outb_p (0xFF, padapter->tag);												// clear the op interrupt
 	outb_p (CMD_DONE, padapter->cmd);											// complete the op
-	goto irq_return;;															// done, but, with what?
+	goto irq_return;															// done, but, with what?
 
 unmapProceed:;
 	if ( !bus )
diff -Nru a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
--- a/drivers/scsi/pci2220i.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/scsi/pci2220i.c	Sat Apr  3 19:38:40 2004
@@ -1389,7 +1389,7 @@
 			 (pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) )
 			{
 			if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) )
-				break;;
+				break;
 
 			if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR )				// is first drive survivor?
 				testsize = SetReconstruct (pdev, 0);
@@ -2613,7 +2613,7 @@
 	
 		if ( ++Installed < MAXADAPTER )
 			continue;
-		break;;
+		break;
 unregister:;
 		scsi_unregister (pshost);
 		}
@@ -2747,7 +2747,7 @@
 		
 		if ( ++Installed < MAXADAPTER )
 			continue;
-		break;;
+		break;
 unregister1:;
 		scsi_unregister (pshost);
 		}
diff -Nru a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
--- a/drivers/scsi/pcmcia/qlogic_stub.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/scsi/pcmcia/qlogic_stub.c	Sat Apr  3 19:38:43 2004
@@ -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_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 @@
 		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 @@
 	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 @@
 	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 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 @@
 		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 -Nru a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
--- a/drivers/scsi/qlogicfas.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/qlogicfas.c	Sat Apr  3 19:38:56 2004
@@ -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 @@
 
 /* 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 @@
  *	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 @@
  *	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 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 @@
 	/* 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		/* 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 @@
 		 *	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 @@
 	 
 	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 @@
 	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 @@
 	}
 	outb(0x12, qbase + 3);	/* done, disconnect */
 	rtrc(1)
-	if ((k = ql_wai()))
+	if ((k = ql_wai(priv)))
 		return (k << 16);
 
 	/*
@@ -487,21 +389,19 @@
 	 */
 	 
 	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 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 @@
 	(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 @@
 	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 @@
 
 	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 @@
 
 	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)
@@ -618,7 +501,7 @@
 			release_region(qbase, 0x10);
 		}
 		if (qbase == 0x430)
-			return NULL;;
+			return NULL;
 	} else
 		printk(KERN_INFO "Ql: Using preset base address of %03x\n", qbase);
 
@@ -641,7 +524,6 @@
 	REG0;
 #endif
 
-#if QL_USE_IRQ
 	/*
 	 *	IRQ probe - toggle pin and check request pending 
 	 */
@@ -668,49 +550,98 @@
 	} 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 @@
  
 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 @@
 
 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 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 @@
 	.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 @@
 };
 
 #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 -Nru a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/qlogicfas.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
--- a/drivers/scsi/qlogicfc.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/scsi/qlogicfc.c	Sat Apr  3 19:38:54 2004
@@ -1778,7 +1778,7 @@
 
 	LEAVE("isp2x00_reset");
 
-	return return_status;;
+	return return_status;
 }
 
 
diff -Nru a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
--- a/drivers/scsi/qlogicisp.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/qlogicisp.c	Sat Apr  3 19:38:56 2004
@@ -1230,7 +1230,7 @@
 
 	LEAVE("isp1020_reset");
 
-	return return_status;;
+	return return_status;
 }
 
 
diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
--- a/drivers/scsi/sata_promise.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/scsi/sata_promise.c	Sat Apr  3 19:38:54 2004
@@ -21,7 +21,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -146,10 +145,6 @@
 
 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,14 +195,11 @@
 
 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,
 	.exec_command		= pdc_exec_command_mmio,
 	.phy_reset		= sata_phy_reset,
-	.phy_config		= pata_phy_config,	/* not a typo */
 	.bmdma_start            = pdc_dma_start,
 	.fill_sg		= pdc_fill_sg,
 	.eng_timeout		= pdc_eng_timeout,
@@ -220,14 +212,11 @@
 
 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,
 	.exec_command		= pdc_exec_command_mmio,
 	.phy_reset		= pdc_20621_phy_reset,
-	.phy_config		= pata_phy_config,	/* not a typo */
 	.bmdma_start            = pdc20621_dma_start,
 	.fill_sg		= pdc20621_fill_sg,
 	.eng_timeout		= pdc_eng_timeout,
@@ -378,19 +367,6 @@
 	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 +1148,16 @@
 {
 	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;
 }
 
@@ -1690,6 +1669,9 @@
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
 		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
 
 	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
 	if (probe_ent == NULL) {
@@ -1809,13 +1791,7 @@
 
 static int __init pdc_sata_init(void)
 {
-	int rc;
-
-	rc = pci_module_init(&pdc_sata_pci_driver);
-	if (rc)
-		return rc;
-
-	return 0;
+	return pci_module_init(&pdc_sata_pci_driver);
 }
 
 
diff -Nru a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
--- a/drivers/scsi/sata_sil.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/scsi/sata_sil.c	Sat Apr  3 19:38:40 2004
@@ -22,7 +22,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -35,7 +34,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_sil"
-#define DRV_VERSION	"0.53"
+#define DRV_VERSION	"0.54"
 
 enum {
 	sil_3112		= 0,
@@ -50,39 +49,18 @@
 	SIL_MASK_4PORT		= SIL_MASK_2PORT |
 				  SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
 
-	SIL_IDE0_TF		= 0x80,
-	SIL_IDE0_CTL		= 0x8A,
-	SIL_IDE0_BMDMA		= 0x00,
-	SIL_IDE0_SCR		= 0x100,
-
-	SIL_IDE1_TF		= 0xC0,
-	SIL_IDE1_CTL		= 0xCA,
-	SIL_IDE1_BMDMA		= 0x08,
-	SIL_IDE1_SCR		= 0x180,
-
-	SIL_IDE2_TF		= 0x280,
-	SIL_IDE2_CTL		= 0x28A,
 	SIL_IDE2_BMDMA		= 0x200,
-	SIL_IDE2_SCR		= 0x300,
-	SIL_INTR_STEERING	= (1 << 1),
-
-	SIL_IDE3_TF		= 0x2C0,
-	SIL_IDE3_CTL		= 0x2CA,
-	SIL_IDE3_BMDMA		= 0x208,
-	SIL_IDE3_SCR		= 0x380,
 
+	SIL_INTR_STEERING	= (1 << 1),
 	SIL_QUIRK_MOD15WRITE	= (1 << 0),
 	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);
 static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void sil_post_set_mode (struct ata_port *ap);
 
 static struct pci_device_id sil_pci_tbl[] = {
 	{ 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
@@ -141,14 +119,12 @@
 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,
 	.exec_command		= ata_exec_command_mmio,
 	.phy_reset		= sata_phy_reset,
-	.phy_config		= pata_phy_config,	/* not a typo */
+	.post_set_mode		= sil_post_set_mode,
 	.bmdma_start            = ata_bmdma_start_mmio,
 	.fill_sg		= ata_fill_sg,
 	.eng_timeout		= ata_eng_timeout,
@@ -166,7 +142,7 @@
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
 		.pio_mask	= 0x03,			/* pio3-4 */
-		.udma_mask	= 0x7f,			/* udma0-6; FIXME */
+		.udma_mask	= 0x3f,			/* udma0-5 */
 		.port_ops	= &sil_ops,
 	}, /* sil_3114 */
 	{
@@ -174,16 +150,61 @@
 		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
 		.pio_mask	= 0x03,			/* pio3-4 */
-		.udma_mask	= 0x7f,			/* udma0-6; FIXME */
+		.udma_mask	= 0x3f,			/* udma0-5 */
 		.port_ops	= &sil_ops,
 	},
 };
 
+/* per-port register offsets */
+/* TODO: we can probably calculate rather than use a table */
+static const struct {
+	unsigned long tf;	/* ATA taskfile register block */
+	unsigned long ctl;	/* ATA control/altstatus register block */
+	unsigned long bmdma;	/* DMA register block */
+	unsigned long scr;	/* SATA control register block */
+	unsigned long sien;	/* SATA Interrupt Enable register */
+	unsigned long xfer_mode;/* data transfer mode register */
+} sil_port[] = {
+	/* port 0 ... */
+	{ 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4 },
+	{ 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4 },
+	{ 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4 },
+	{ 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4 },
+	/* ... port 3 */
+};
+
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
 
+static void sil_post_set_mode (struct ata_port *ap)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	struct ata_device *dev;
+	void *addr = host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
+	u32 tmp, dev_mode[2];
+	unsigned int i;
+
+	for (i = 0; i < 2; i++) {
+		dev = &ap->device[i];
+		if (!ata_dev_present(dev))
+			dev_mode[i] = 0;	/* PIO0/1/2 */
+		else if (dev->flags & ATA_DFLAG_PIO)
+			dev_mode[i] = 1;	/* PIO3/4 */
+		else
+			dev_mode[i] = 3;	/* UDMA */
+		/* value 2 indicates MDMA */
+	}
+
+	tmp = readl(addr);
+	tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));
+	tmp |= dev_mode[0];
+	tmp |= (dev_mode[1] << 4);
+	writel(tmp, addr);
+	readl(addr);	/* flush */
+}
+
 static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
 {
 	unsigned long offset = ap->ioaddr.scr_addr;
@@ -250,13 +271,9 @@
 static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
 {
 	unsigned int n, quirks = 0;
-	u32 class_rev = 0;
 	const char *s = &dev->product[0];
 	unsigned int len = strnlen(s, sizeof(dev->product));
 
-	pci_read_config_dword(ap->host_set->pdev, PCI_CLASS_REVISION, &class_rev);
-	class_rev &= 0xff;
-
 	/* ATAPI specifies that empty space is blank-filled; remove blanks */
 	while ((len > 0) && (s[len - 1] == ' '))
 		len--;
@@ -269,7 +286,7 @@
 		}
 	
 	/* limit requests to 15 sectors */
-	if ((class_rev <= 0x01) && (quirks & SIL_QUIRK_MOD15WRITE)) {
+	if (quirks & SIL_QUIRK_MOD15WRITE) {
 		printk(KERN_INFO "ata%u(%u): applying Seagate errata fix\n",
 		       ap->id, dev->devno);
 		ap->host->max_sectors = 15;
@@ -278,7 +295,6 @@
 	}
 
 	/* limit to udma5 */
-	/* is this for (class_rev <= 0x01) only, too? */
 	if (quirks & SIL_QUIRK_UDMA5MAX) {
 		printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n",
 		       ap->id, dev->devno, s);
@@ -287,22 +303,6 @@
 	}
 }
 
-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;
@@ -310,6 +310,7 @@
 	unsigned long base;
 	void *mmio_base;
 	int rc;
+	unsigned int i;
 	u32 tmp, irq_mask;
 
 	if (!printed_version++)
@@ -330,6 +331,9 @@
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
 		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
 
 	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
 	if (probe_ent == NULL) {
@@ -359,31 +363,17 @@
 	probe_ent->mmio_base = mmio_base;
 
 	base = (unsigned long) mmio_base;
-	probe_ent->port[0].cmd_addr = base + SIL_IDE0_TF;
-	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].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;
-	ata_std_ports(&probe_ent->port[1]);
 
-	if (ent->driver_data == sil_3114) {
-		probe_ent->port[2].cmd_addr = base + SIL_IDE2_TF;
-		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].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;
-		ata_std_ports(&probe_ent->port[3]);
+	for (i = 0; i < probe_ent->n_ports; i++) {
+		probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
+		probe_ent->port[i].altstatus_addr =
+		probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
+		probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
+		probe_ent->port[i].scr_addr = base + sil_port[i].scr;
+		ata_std_ports(&probe_ent->port[i]);
+	}
 
+	if (ent->driver_data == sil_3114) {
 		irq_mask = SIL_MASK_4PORT;
 
 		/* flip the magic "make 4 ports work" bit */
@@ -404,6 +394,11 @@
 		readl(mmio_base + SIL_SYSCFG);	/* flush */
 	}
 
+	/* mask all SATA phy-related interrupts */
+	/* TODO: unmask bit 6 (SError N bit) for hotplug */
+	for (i = 0; i < probe_ent->n_ports; i++)
+		writel(0, mmio_base + sil_port[i].sien);
+
 	pci_set_master(pdev);
 
 	/* FIXME: check ata_device_add return value */
@@ -423,13 +418,7 @@
 
 static int __init sil_init(void)
 {
-	int rc;
-
-	rc = pci_module_init(&sil_pci_driver);
-	if (rc)
-		return rc;
-
-	return 0;
+	return pci_module_init(&sil_pci_driver);
 }
 
 static void __exit sil_exit(void)
diff -Nru a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
--- a/drivers/scsi/sata_svw.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/scsi/sata_svw.c	Sat Apr  3 19:38:44 2004
@@ -103,13 +103,13 @@
 		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 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,14 +221,11 @@
 
 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,
 	.exec_command		= ata_exec_command_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,
@@ -261,13 +240,16 @@
 {
 	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;
@@ -307,6 +289,9 @@
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
 		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
 
 	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
 	if (probe_ent == NULL) {
@@ -350,7 +335,7 @@
 	 * if we don't fill these
 	 */
 	probe_ent->pio_mask = 0x1f;
-	probe_ent->udma_mask = 0x3f;
+	probe_ent->udma_mask = 0x7f;
 
 	/* We have 4 ports per PCI function */
 	k2_sata_setup_port(&probe_ent->port[0], base + 0 * K2_SATA_PORT_OFFSET);
@@ -392,15 +377,8 @@
 
 static int __init k2_sata_init(void)
 {
-	int rc;
-
-	rc = pci_module_init(&k2_sata_pci_driver);
-	if (rc)
-		return rc;
-
-	return 0;
+	return pci_module_init(&k2_sata_pci_driver);
 }
-
 
 static void __exit k2_sata_exit(void)
 {
diff -Nru a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
--- a/drivers/scsi/sata_via.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/sata_via.c	Sat Apr  3 19:38:41 2004
@@ -22,7 +22,6 @@
 
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -32,23 +31,35 @@
 #include "scsi.h"
 #include "hosts.h"
 #include <linux/libata.h>
+#include <asm/io.h>
 
 #define DRV_NAME	"sata_via"
-#define DRV_VERSION	"0.11"
+#define DRV_VERSION	"0.20"
 
 enum {
 	via_sata		= 0,
+
+	SATA_CHAN_ENAB		= 0x40, /* SATA channel enable */
+	SATA_INT_GATE		= 0x41, /* SATA interrupt gating */
+	SATA_NATIVE_MODE	= 0x42, /* Native mode enable */
+	SATA_PATA_SHARING	= 0x49, /* PATA/SATA sharing func ctrl */
+
+	PORT0			= (1 << 1),
+	PORT1			= (1 << 0),
+
+	ENAB_ALL		= PORT0 | PORT1,
+
+	INT_GATE_ALL		= PORT0 | PORT1,
+
+	NATIVE_MODE_ALL		= (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
+
+	SATA_EXT_PHY		= (1 << 6), /* 0==use PATA, 1==ext phy */
+	SATA_2DEV		= (1 << 5), /* SATA is master/slave */
 };
 
 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;
+static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static struct pci_device_id svia_pci_tbl[] = {
 	{ 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, via_sata },
@@ -82,17 +93,14 @@
 };
 
 static struct ata_port_operations svia_sata_ops = {
-	.port_disable		= svia_port_disable,
-	.set_piomode		= svia_set_piomode,
-	.set_udmamode		= svia_set_udmamode,
+	.port_disable		= ata_port_disable,
 
 	.tf_load		= ata_tf_load_pio,
 	.tf_read		= ata_tf_read_pio,
 	.check_status		= ata_check_status_pio,
 	.exec_command		= ata_exec_command_pio,
 
-	.phy_reset		= svia_sata_phy_reset,
-	.phy_config		= pata_phy_config,	/* not a typo */
+	.phy_reset		= sata_phy_reset,
 
 	.bmdma_start            = ata_bmdma_start_pio,
 	.fill_sg		= ata_fill_sg,
@@ -100,102 +108,39 @@
 
 	.irq_handler		= ata_interrupt,
 
+	.scr_read		= svia_scr_read,
+	.scr_write		= svia_scr_write,
+
 	.port_start		= ata_port_start,
 	.port_stop		= ata_port_stop,
 };
 
-static struct ata_port_info svia_port_info[] = {
-	/* via_sata */
-	{
-		.sht		= &svia_sht,
-		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY
-				  | ATA_FLAG_SRST,
-		.pio_mask	= 0x03,	/* pio3-4 */
-		.udma_mask	= 0x7f,	/* udma0-6 ; FIXME */
-		.port_ops	= &svia_sata_ops,
-	},
-};
-
-static struct pci_bits svia_enable_bits[] = {
-	{ 0x40U, 1U, 0x02UL, 0x02UL },	/* port 0 */
-	{ 0x40U, 1U, 0x01UL, 0x01UL },	/* port 1 */
-};
-
-
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
 MODULE_LICENSE("GPL");
 MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
 
-/**
- *	svia_sata_phy_reset -
- *	@ap:
- *
- *	LOCKING:
- *
- */
-
-static void svia_sata_phy_reset(struct ata_port *ap)
+static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
 {
-	if (!pci_test_config_bits(ap->host_set->pdev,
-				  &svia_enable_bits[ap->port_no])) {
-		ata_port_disable(ap);
-		printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
-		return;
-	}
-
-	ata_port_probe(ap);
-	if (ap->flags & ATA_FLAG_PORT_DISABLED)
-		return;
-
-	ata_bus_reset(ap);
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
 }
 
-/**
- *	svia_port_disable -
- *	@ap:
- *
- *	LOCKING:
- *
- */
-
-static void svia_port_disable(struct ata_port *ap)
+static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
-	ata_port_disable(ap);
-
-	/* FIXME */
-}
-
-/**
- *	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? */
+	if (sc_reg > SCR_CONTROL)
+		return;
+	outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
 }
 
-/**
- *	svia_set_udmamode -
- *	@ap:
- *	@adev:
- *	@udma:
- *
- *	LOCKING:
- *
- */
+static const unsigned int svia_bar_sizes[] = {
+	8, 4, 8, 4, 16, 256
+};
 
-static void svia_set_udmamode (struct ata_port *ap, struct ata_device *adev,
-			      unsigned int udma)
+static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
 {
-	/* FIXME: needed? */
+	return addr + (port * 128);
 }
 
 /**
@@ -212,19 +157,131 @@
 static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
-	struct ata_port_info *port_info[1];
-	unsigned int n_ports = 1;
+	unsigned int i;
+	int rc;
+	struct ata_probe_ent *probe_ent;
+	u8 tmp8;
 
 	if (!printed_version++)
 		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
 
-	/* no hotplugging support (FIXME) */
-	if (!in_module_init)
-		return -ENODEV;
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
 
-	port_info[0] = &svia_port_info[ent->driver_data];
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
+	if (tmp8 & SATA_2DEV) {
+		printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		rc = -EIO;
+		goto err_out_regions;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
+		if ((pci_resource_start(pdev, i) == 0) ||
+		    (pci_resource_len(pdev, i) < svia_bar_sizes[i])) {
+			printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
+			       pci_name(pdev), i,
+			       pci_resource_start(pdev, i),
+			       pci_resource_len(pdev, i));
+			rc = -ENODEV;
+			goto err_out_regions;
+		}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
 
-	return ata_pci_init_one(pdev, port_info, n_ports);
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (!probe_ent) {
+		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+		       pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	INIT_LIST_HEAD(&probe_ent->node);
+	probe_ent->pdev = pdev;
+	probe_ent->sht = &svia_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SRST |
+				ATA_FLAG_NO_LEGACY;
+	probe_ent->port_ops = &svia_sata_ops;
+	probe_ent->n_ports = 2;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->udma_mask = 0x7f;
+
+	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[0].bmdma_addr = pci_resource_start(pdev, 4);
+	probe_ent->port[0].scr_addr =
+		svia_scr_addr(pci_resource_start(pdev, 5), 0);
+
+	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;
+	probe_ent->port[1].scr_addr =
+		svia_scr_addr(pci_resource_start(pdev, 5), 1);
+
+	pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
+	printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n",
+	       pci_name(pdev),
+	       (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
+
+	/* make sure SATA channels are enabled */
+	pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
+	if ((tmp8 & ENAB_ALL) != ENAB_ALL) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= ENAB_ALL;
+		pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
+	}
+
+	/* make sure interrupts for each channel sent to us */
+	pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
+	if ((tmp8 & INT_GATE_ALL) != INT_GATE_ALL) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= INT_GATE_ALL;
+		pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
+	}
+
+	/* make sure native mode is enabled */
+	pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
+	if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= NATIVE_MODE_ALL;
+		pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
+	}
+
+	pci_set_master(pdev);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
 }
 
 /**
@@ -238,17 +295,7 @@
 
 static int __init svia_init(void)
 {
-	int rc;
-
-	DPRINTK("pci_module_init\n");
-	rc = pci_module_init(&svia_pci_driver);
-	if (rc)
-		return rc;
-
-	in_module_init = 0;
-
-	DPRINTK("done\n");
-	return 0;
+	return pci_module_init(&svia_pci_driver);
 }
 
 /**
diff -Nru a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/sata_vsc.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,376 @@
+/*
+ *  sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
+ *
+ *  Copyright 2004 SGI
+ *
+ *  Bits from Jeff Garzik, Copyright RedHat, Inc.
+ *
+ *  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.
+ */
+
+#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,
+	.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 __devinit 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 __devinit 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, 0xFFFFFFFFULL);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, 0xFFFFFFFFULL);
+	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 = 0x7f;
+
+	/* 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;
+}
+
+
+/*
+ * 0x1725/0x7174 is the Vitesse VSC-7174
+ * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical
+ * compatibility is untested as of yet
+ */
+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)
+{
+	return pci_module_init(&vsc_sata_pci_driver);
+}
+
+
+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 -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/scsi/scsi.c	Sat Apr  3 19:38:43 2004
@@ -53,6 +53,8 @@
 #include <linux/spinlock.h>
 #include <linux/kmod.h>
 #include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
 
 #include <scsi/scsi_host.h>
 #include "scsi.h"
@@ -104,7 +106,7 @@
 	"Communications   ",
 	"Unknown          ",
 	"Unknown          ",
-	"Unknown          ",
+	"RAID             ",
 	"Enclosure        ",
 };
 
@@ -1097,7 +1099,7 @@
 	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) {
@@ -1130,6 +1132,38 @@
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int scsi_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *hcpu)
+{
+	int cpu = (unsigned long)hcpu;
+
+	switch(action) {
+	case CPU_DEAD:
+		/* Drain scsi_done_q. */
+		local_irq_disable();
+		list_splice_init(&per_cpu(scsi_done_q, cpu),
+				 &__get_cpu_var(scsi_done_q));
+		raise_softirq_irqoff(SCSI_SOFTIRQ);
+		local_irq_enable();
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __devinitdata scsi_cpu_nb = {
+	.notifier_call	= scsi_cpu_notify,
+};
+
+#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb)
+#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb)
+#else
+#define register_scsi_cpu()
+#define unregister_scsi_cpu()
+#endif /* CONFIG_HOTPLUG_CPU */
+
 MODULE_DESCRIPTION("SCSI core");
 MODULE_LICENSE("GPL");
 
@@ -1164,6 +1198,7 @@
 
 	devfs_mk_dir("scsi");
 	open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
+	register_scsi_cpu();
 	printk(KERN_NOTICE "SCSI subsystem initialized\n");
 	return 0;
 
@@ -1191,6 +1226,7 @@
 	devfs_remove("scsi");
 	scsi_exit_procfs();
 	scsi_exit_queue();
+	unregister_scsi_cpu();
 }
 
 subsys_initcall(init_scsi);
diff -Nru a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
--- a/drivers/scsi/scsi_devinfo.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/scsi_devinfo.c	Sat Apr  3 19:38:42 2004
@@ -94,95 +94,93 @@
 	 * 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 -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/scsi/scsi_error.c	Sat Apr  3 19:38:40 2004
@@ -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 @@
 			(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 @@
 }
 
 /**
+ * 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 @@
 		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 @@
 		 */
 	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 @@
 			       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 -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/scsi/scsi_lib.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	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 @@
  *		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 @@
 		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 @@
 	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 @@
 			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 @@
 		}
 		/* OK, we only allow special commands (i.e. not
 		 * user initiated ones */
-		specials_only = 1;
+		specials_only = sdev->sdev_state;
 	}
 
 	/*
@@ -965,6 +995,9 @@
 	} 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 @@
 	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 @@
 
 	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 -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h	Sat Apr  3 19:38:45 2004
+++ b/drivers/scsi/scsi_priv.h	Sat Apr  3 19:38:45 2004
@@ -155,6 +155,7 @@
 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 -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/scsi/scsi_scan.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 	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 @@
 			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 @@
 		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 @@
 	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 @@
 	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 @@
 	} 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 @@
 
 	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 -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/scsi_sysfs.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
  * 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(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 @@
 	&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 @@
  **/
 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 @@
 		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 @@
 		}
 	}
 
+ 	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 @@
 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 @@
 
 	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 -Nru a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/scsi_transport_fc.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/scsi_transport_spi.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c
--- a/drivers/scsi/scsiiom.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/scsi/scsiiom.c	Sat Apr  3 19:38:41 2004
@@ -1674,7 +1674,7 @@
 #endif	
 	    psrb  = psrb2;
 	}
-	pdcb->GoingSRBCnt = 0;;
+	pdcb->GoingSRBCnt = 0;
 	pdcb->pGoingSRB = NULL;
 	pdcb->TagMask = 0;
 	pdcb = pdcb->pNextDCB;
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/scsi/sd.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 	.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 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 @@
 	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 @@
 	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 @@
 	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 -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/scsi/sg.c	Sat Apr  3 19:38:43 2004
@@ -1256,7 +1256,6 @@
 	SRpnt->sr_request->rq_disk = NULL; /* "sg" _disowns_ request blk */
 
 	srp->my_cmdp = NULL;
-	srp->done = 1;
 
 	SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n",
 		sdp->disk->disk_name, srp->header.pack_id, (int) SRpnt->sr_result));
@@ -1312,8 +1311,9 @@
 	}
 	if (sfp && srp) {
 		/* Now wake up any sg_read() that is waiting for this packet. */
-		wake_up_interruptible(&sfp->read_wait);
 		kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
+		srp->done = 1;
+		wake_up_interruptible(&sfp->read_wait);
 	}
 }
 
@@ -1409,7 +1409,6 @@
 	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 @@
 				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 @@
 out:
 	put_disk(disk);
 	if (cdev)
-		kobject_put(&cdev->kobj);
+		cdev_del(cdev);
 	return error;
 }
 
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/sr.c	Sat Apr  3 19:38:42 2004
@@ -566,12 +566,16 @@
 	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);
+	disk->flags |= GENHD_FL_REMOVABLE;
 	add_disk(disk);
 
 	printk(KERN_DEBUG
@@ -695,7 +699,7 @@
 static void get_capabilities(struct scsi_cd *cd)
 {
 	unsigned char *buffer;
-	int rc, n, mrw_write = 0, mrw = 1;
+	int rc, n, mrw_write = 0, mrw = 1,ram_write=0;
 	struct scsi_mode_data data;
 	struct scsi_request *SRpnt;
 	unsigned char cmd[MAX_COMMAND_SIZE];
@@ -780,6 +784,11 @@
 	if (!mrw_write)
 		cd->cdi.mask |= CDC_MRW_W;
 
+	if (cdrom_is_random_writable(&cd->cdi, &ram_write))
+		cd->cdi.mask |= CDC_RAM;
+	if (!ram_write)
+		cd->cdi.mask |= CDC_RAM;
+
 	n = data.header_length + data.block_descriptor_length;
 	cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
 	cd->readcd_known = 1;
@@ -829,8 +838,8 @@
 	/*
 	 * if DVD-RAM of MRW-W, we are randomly writeable
 	 */
-	if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W)) !=
-			(CDC_DVD_RAM | CDC_MRW_W)) {
+	if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) !=
+			(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) {
 		cd->device->writeable = 1;
 		set_disk_ro(cd->disk, 0);
 	}
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/scsi/st.c	Sat Apr  3 19:38:45 2004
@@ -17,7 +17,7 @@
    Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
  */
 
-static char *verstr = "20040213";
+static char *verstr = "20040318";
 
 #include <linux/module.h>
 
@@ -121,7 +121,15 @@
 };
 #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,6 @@
 				       dev_num);
 				goto out_free_tape;
 			}
-			snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%sm%d%s", disk->disk_name,
-				 mode, j ? "n" : "");
 			cdev->owner = THIS_MODULE;
 			cdev->ops = &st_fops;
 
@@ -3909,22 +3915,26 @@
 	}
 
 	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 +3954,7 @@
 		}
 	}
 	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 +3987,9 @@
 			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)));
@@ -4182,20 +4193,25 @@
 
 static void do_create_class_files(Scsi_Tape *STp, int dev_num, int mode)
 {
-	int rew, error;
+	int i, rew, error;
+	char name[10];
 	struct class_device *st_class_member;
 
 	if (!st_sysfs_class)
 		return;
 
 	for (rew=0; rew < 2; rew++) {
+		/* 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(name, 10, "%s%s%s", rew ? "n" : "",
+			 STp->disk->disk_name, st_formats[i]);
 		st_class_member =
 			class_simple_device_add(st_sysfs_class,
 						MKDEV(SCSI_TAPE_MAJOR,
 						      TAPE_MINOR(dev_num, mode, rew)),
-						&STp->device->sdev_gendev, "%s",
-						STp->modes[mode].cdevs[rew]->kobj.name);
-		if (!st_class_member) {
+						&STp->device->sdev_gendev, "%s", name);
+		if (IS_ERR(st_class_member)) {
 			printk(KERN_WARNING "st%d: class_simple_device_add failed\n",
 			       dev_num);
 			goto out;
diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h
--- a/drivers/scsi/st.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/scsi/st.h	Sat Apr  3 19:38:55 2004
@@ -50,6 +50,8 @@
 	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 -Nru a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Sat Apr  3 19:38:56 2004
@@ -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 -Nru a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h
--- a/drivers/scsi/sym53c8xx_2/sym_defs.h	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_defs.h	Sat Apr  3 19:38:42 2004
@@ -127,135 +127,6 @@
 };
 
 /*
- *	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 -Nru a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c
--- a/drivers/scsi/sym53c8xx_2/sym_fw.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.c	Sat Apr  3 19:38:56 2004
@@ -135,7 +135,7 @@
  *  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 @@
  *  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 @@
  *  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 @@
  *  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 @@
  *  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 @@
 /*
  *  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 -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	Sat Apr  3 19:38:57 2004
@@ -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 @@
 	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 @@
 		__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 @@
 	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 @@
 /*
  *  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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 #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 @@
 	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 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 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 -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h	Sat Apr  3 19:38:56 2004
@@ -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 @@
 	char	inst_name[16];
 };
 
+struct sym_nvram;
+
 struct sym_device {
 	struct pci_dev *pdev;
 	struct sym_slot  s;
@@ -420,12 +442,7 @@
 	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 
diff -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c	Sat Apr  3 19:38:40 2004
@@ -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 @@
 	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 @@
 	/*
 	 *  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 @@
 		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 -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h
--- a/drivers/scsi/sym53c8xx_2/sym_hipd.h	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h	Sat Apr  3 19:38:42 2004
@@ -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 @@
 
 #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 @@
  *  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;
 
@@ -1321,15 +1298,6 @@
 /*
  *  MEMORY ALLOCATOR.
  */
-
-/*
- *  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.
diff -Nru a/drivers/scsi/sym53c8xx_2/sym_misc.c b/drivers/scsi/sym53c8xx_2/sym_misc.c
--- a/drivers/scsi/sym53c8xx_2/sym_misc.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_misc.c	Sat Apr  3 19:38:55 2004
@@ -315,7 +315,7 @@
 	 */
 	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 @@
 	    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 -Nru a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h
--- a/drivers/scsi/sym53c8xx_2/sym_misc.h	Sat Apr  3 19:38:56 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_misc.h	Sat Apr  3 19:38:56 2004
@@ -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 @@
 #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.
@@ -273,24 +201,5 @@
  _U_(a, 0)_U_(a, 1)_U_(a, 2)_U_(a, 3)_U_(a, 4)_U_(a, 5)_U_(a, 6)_U_(a, 7) \
  _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 -Nru a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c
--- a/drivers/scsi/sym53c8xx_2/sym_nvram.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c	Sat Apr  3 19:38:44 2004
@@ -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 @@
 	}
 }
 #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 */
 
 
@@ -382,6 +379,61 @@
 
 	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 -Nru a/drivers/scsi/sym53c8xx_2/sym_nvram.h b/drivers/scsi/sym53c8xx_2/sym_nvram.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h
--- a/drivers/scsi/sym53c8xx_comm.h	Sat Apr  3 19:38:43 2004
+++ b/drivers/scsi/sym53c8xx_comm.h	Sat Apr  3 19:38:43 2004
@@ -703,7 +703,8 @@
 #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 @@
 	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 @@
 #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 -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
--- a/drivers/scsi/u14-34f.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/scsi/u14-34f.c	Sat Apr  3 19:38:42 2004
@@ -1184,17 +1184,17 @@
    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 -Nru a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
--- a/drivers/scsi/wd33c93.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/scsi/wd33c93.c	Sat Apr  3 19:38:45 2004
@@ -2056,7 +2056,7 @@
 		return 0;
 	}
 	if (off > 0x40000)	/* ALWAYS stop after 256k bytes have been read */
-		stop = 1;;
+		stop = 1;
 	if (hd->proc & PR_STOP)	/* stop every other time */
 		stop = 1;
 	return strlen(bp);
diff -Nru a/drivers/serial/21285.c b/drivers/serial/21285.c
--- a/drivers/serial/21285.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/serial/21285.c	Sat Apr  3 19:38:54 2004
@@ -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>
@@ -510,6 +511,7 @@
 	.owner			= THIS_MODULE,
 	.driver_name		= "ttyFB",
 	.dev_name		= "ttyFB",
+	.devfs_name             = "ttyFB",
 	.major			= SERIAL_21285_MAJOR,
 	.minor			= SERIAL_21285_MINOR,
 	.nr			= 1,
@@ -542,3 +544,4 @@
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.37 $");
+MODULE_ALIAS_CHARDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c
--- a/drivers/serial/8250.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/serial/8250.c	Sat Apr  3 19:38:41 2004
@@ -30,6 +30,7 @@
 #include <linux/serial.h>
 #include <linux/serialP.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -2194,3 +2195,4 @@
 MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
 MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
 #endif
+MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
diff -Nru a/drivers/serial/8250_acpi.c b/drivers/serial/8250_acpi.c
--- a/drivers/serial/8250_acpi.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/serial/8250_acpi.c	Sat Apr  3 19:38:56 2004
@@ -134,8 +134,7 @@
 	}
 
 	serial_req.baud_base = BASE_BAUD;
-	serial_req.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF |
-			   UPF_AUTO_IRQ  | UPF_RESOURCES;
+	serial_req.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_RESOURCES;
 
 	priv->line = register_serial(&serial_req);
 	if (priv->line < 0) {
diff -Nru a/drivers/serial/8250_hcdp.c b/drivers/serial/8250_hcdp.c
--- a/drivers/serial/8250_hcdp.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/serial/8250_hcdp.c	Sat Apr  3 19:38:55 2004
@@ -186,8 +186,6 @@
 		port.irq = gsi;
 #endif
 		port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_RESOURCES;
-		if (gsi)
-			port.flags |= ASYNC_AUTO_IRQ;
 
 		/*
 		 * Note: the above memset() initializes port.line to 0,
diff -Nru a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
--- a/drivers/serial/8250_pnp.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/serial/8250_pnp.c	Sat Apr  3 19:38:41 2004
@@ -266,6 +266,8 @@
 	{	"RSS00A0",		0	},
 	/* Viking 56K FAX INT */
 	{	"RSS0262",		0	},
+	/* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
+	{       "RSS0250",              0       },
 	/* SupraExpress 28.8 Data/Fax PnP modem */
 	{	"SUP1310",		0	},
 	/* SupraExpress 33.6 Data/Fax PnP modem */
@@ -283,6 +285,8 @@
 	/* 3Com Corp. */
 	/* Gateway Telepath IIvi 33.6 */
 	{	"USR0000",		0	},
+	/* U.S. Robotics Sporster 33.6K Fax INT PnP */
+	{	"USR0002",		0	},
 	/*  Sportster Vi 14.4 PnP FAX Voicemail */
 	{	"USR0004",		0	},
 	/* U.S. Robotics 33.6K Voice INT PnP */
@@ -315,6 +319,8 @@
 	{	"USR9180",		0	},
 	/* U.S. Robotics 56K Voice INT PnP*/
 	{	"USR9190",		0	},
+	/* Rockwell's (PORALiNK) 33600 INT PNP */
+	{	"WCI0003",		0	},
 	/* Unkown PnP modems */
 	{	"PNPCXXX",		UNKNOWN_DEV	},
 	/* More unkown PnP modems */
@@ -390,7 +396,7 @@
 	return -ENODEV;
 }
 
-static int
+static int __devinit
 serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
 {
 	struct serial_struct serial_req;
@@ -420,7 +426,7 @@
 
 }
 
-static void serial_pnp_remove(struct pnp_dev * dev)
+static void __devexit serial_pnp_remove(struct pnp_dev * dev)
 {
 	int line = (int)pnp_get_drvdata(dev);
 	if (line)
diff -Nru a/drivers/serial/Kconfig b/drivers/serial/Kconfig
--- a/drivers/serial/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/drivers/serial/Kconfig	Sat Apr  3 19:38:55 2004
@@ -1,7 +1,7 @@
 #
 # Serial device configuration
 #
-# $Id: Config.in,v 1.15 2002/07/06 17:16:24 rmk Exp $
+# $Id: Kconfig,v 1.11 2004/03/11 18:08:04 lethal Exp $
 #
 
 menu "Serial drivers"
@@ -174,32 +174,6 @@
 	  system, say Y to this option.  The driver can handle 1, 2, or 3 port
 	  cards.  If unsure, say N.
 
-config SERIAL_ANAKIN
-	bool "Anakin serial port support"
-	depends on ARM && ARCH_ANAKIN
-	select SERIAL_CORE
-	help
-	  ::: To be written :::
-
-config SERIAL_ANAKIN_CONSOLE
-	bool "Console on Anakin serial port"
-	depends on SERIAL_ANAKIN
-	select SERIAL_CORE_CONSOLE
-	help
-	  Even if you say Y here, the currently visible virtual console
-	  (/dev/tty0) will still be used as the system console by default, but
-	  you can alter that using a kernel command line option such as
-	  "console=ttyAN0". (Try "man bootparam" or see the documentation of
-	  your boot loader (lilo or loadlin) about how to pass options to the
-	  kernel at boot time.)
-
-config ANAKIN_DEFAULT_BAUDRATE
-	int "Default Anakin serial baudrate"
-	depends on SERIAL_ANAKIN
-	default "9600"
-	help
-	  ::: To be written :::
-
 config SERIAL_AMBA
 	tristate "ARM AMBA serial port support"
 	depends on ARM_AMBA
@@ -501,6 +475,16 @@
 config SERIAL98_CONSOLE
         bool "Support for console on PC-9800 standard serial port"
         depends on SERIAL98=y
+	select SERIAL_CORE_CONSOLE
+
+config SERIAL_SH_SCI
+	tristate "SH SCI(F) serial port support"
+	depends on SUPERH
+	select SERIAL_CORE
+
+config SERIAL_SH_SCI_CONSOLE
+	bool "Support for console on SH SCI(F)"
+	depends on SERIAL_SH_SCI=y
 	select SERIAL_CORE_CONSOLE
 
 config SERIAL_AU1X00
diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile
--- a/drivers/serial/Makefile	Sat Apr  3 19:38:43 2004
+++ b/drivers/serial/Makefile	Sat Apr  3 19:38:43 2004
@@ -16,7 +16,6 @@
 obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
 obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
 obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
-obj-$(CONFIG_SERIAL_ANAKIN) += anakin.o
 obj-$(CONFIG_SERIAL_AMBA) += amba.o
 obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
 obj-$(CONFIG_SERIAL_PXA) += pxa.o
@@ -36,3 +35,4 @@
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_AU1X00) += au1x00_uart.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
+obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
diff -Nru a/drivers/serial/amba.c b/drivers/serial/amba.c
--- a/drivers/serial/amba.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/serial/amba.c	Sat Apr  3 19:38:41 2004
@@ -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_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 -Nru a/drivers/serial/anakin.c b/drivers/serial/anakin.c
--- a/drivers/serial/anakin.c	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,543 +0,0 @@
-/*
- *  linux/drivers/char/anakin.c
- *
- *  Based on driver for AMBA serial ports, by ARM Limited,
- *  Deep Blue Solutions Ltd., Linus Torvalds and Theodore Ts'o.
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- *  Copyright (C) 2001 Blue Mug, Inc. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   20-Apr-2001 TTC	Created
- *   05-May-2001 W/TTC	Updated for serial_core.c
- *   27-Jun-2001 jonm	Minor changes; add mctrl support, switch to 
- *   			SA_INTERRUPT. Works reliably now. No longer requires
- *   			changes to the serial_core API.
- *
- *  $Id: anakin.c,v 1.32 2002/07/28 10:03:27 rmk Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <linux/serial_core.h>
-
-#include <asm/arch/serial_reg.h>
-
-#define UART_NR			5
-
-#define SERIAL_ANAKIN_NAME	"ttyAN"
-#define SERIAL_ANAKIN_MAJOR	204
-#define SERIAL_ANAKIN_MINOR	32
-
-static unsigned int txenable[NR_IRQS];		/* Software interrupt register */
-
-static inline unsigned int
-anakin_in(struct uart_port *port, unsigned int offset)
-{
-	return __raw_readl(port->base + offset);
-}
-
-static inline void
-anakin_out(struct uart_port *port, unsigned int offset, unsigned int value)
-{
-	__raw_writel(value, port->base + offset);
-}
-
-static void
-anakin_stop_tx(struct uart_port *port, unsigned int tty_stop)
-{
-	txenable[port->irq] = 0;
-}
-
-static inline void
-anakin_transmit_buffer(struct uart_port *port)
-{
-	struct circ_buf *xmit = &port->info->xmit;
-
-	while (!(anakin_in(port, 0x10) & TXEMPTY))
-		barrier();
-	anakin_out(port, 0x14, xmit->buf[xmit->tail]);
-	anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
-	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
-        port->icount.tx++;
-
-	if (uart_circ_empty(xmit))
-		anakin_stop_tx(port, 0); 
-}
-
-static inline void
-anakin_transmit_x_char(struct uart_port *port)
-{
-	anakin_out(port, 0x14, port->x_char);
-	anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
-	port->icount.tx++;
-	port->x_char = 0;
-}
-
-static void
-anakin_start_tx(struct uart_port *port, unsigned int tty_start)
-{
-	// is it this... or below
-	if (!txenable[port->irq]) {
-		txenable[port->irq] = TXENABLE;
-
-		if ((anakin_in(port, 0x10) & TXEMPTY)) {
-		    anakin_transmit_buffer(port);
-		}
-	}
-}
-
-static void
-anakin_stop_rx(struct uart_port *port)
-{
-	while (anakin_in(port, 0x10) & RXRELEASE) 
-	    anakin_in(port, 0x14);
-	anakin_out(port, 0x18, anakin_in(port, 0x18) | BLOCKRX);
-}
-
-static void
-anakin_enable_ms(struct uart_port *port)
-{
-}
-
-static inline void
-anakin_rx_chars(struct uart_port *port)
-{
-	unsigned int ch;
-	struct tty_struct *tty = port->info->tty;
-
-	if (!(anakin_in(port, 0x10) & RXRELEASE))
-		return;
-
-	ch = anakin_in(port, 0x14) & 0xff;
-
-	if (tty->flip.count < TTY_FLIPBUF_SIZE) {
-		*tty->flip.char_buf_ptr++ = ch;
-		*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
-		port->icount.rx++;
-		tty->flip.count++;
-	} 
-	tty_flip_buffer_push(tty);
-}
-
-static inline void
-anakin_overrun_chars(struct uart_port *port)
-{
-	unsigned int ch;
-
-	ch = anakin_in(port, 0x14);
-	port->icount.overrun++;
-}
-
-static inline void
-anakin_tx_chars(struct uart_port *port)
-{
-	struct circ_buf *xmit = &port->info->xmit;
-
-	if (port->x_char) {
-		anakin_transmit_x_char(port);
-		return; 
-	}
-
-	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-		anakin_stop_tx(port, 0);
-		return;
-	}
-
-	anakin_transmit_buffer(port);
-
-	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-		uart_write_wakeup(port);
-}
-
-static void
-anakin_int(int irq, void *dev_id, struct pt_regs *regs)
-{
-	unsigned int status;
-	struct uart_port *port = dev_id;
-
-	status = anakin_in(port, 0x1c);
-
-	if (status & RX) 
-		anakin_rx_chars(port);
-
-	if (status & OVERRUN) 
-		anakin_overrun_chars(port);
-
-	if (txenable[port->irq] && (status & TX)) 
-		anakin_tx_chars(port);
-}
-
-static unsigned int
-anakin_tx_empty(struct uart_port *port)
-{
-	return anakin_in(port, 0x10) & TXEMPTY ? TIOCSER_TEMT : 0;
-}
-
-static unsigned int
-anakin_get_mctrl(struct uart_port *port)
-{
-	unsigned int status = 0;
-
-	status |= (anakin_in(port, 0x10) & CTS ? TIOCM_CTS : 0);
-	status |= (anakin_in(port, 0x18) & DCD ? TIOCM_CAR : 0);
-	status |= (anakin_in(port, 0x18) & DTR ? TIOCM_DTR : 0);
-	status |= (anakin_in(port, 0x18) & RTS ? TIOCM_RTS : 0);
-	
-	return status;
-}
-
-static void
-anakin_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-	unsigned int status;
-
-	status = anakin_in(port, 0x18);
-
-	if (mctrl & TIOCM_RTS) 
-		status |= RTS;
-	else 
-		status &= ~RTS;
-
-	if (mctrl & TIOCM_CAR)
-		status |= DCD;
-	else 
-		status &= ~DCD;
-
-	anakin_out(port, 0x18, status);
-}
-
-static void
-anakin_break_ctl(struct uart_port *port, int break_state)
-{
-	unsigned long flags;
-	unsigned int status;
-
-	spin_lock_irqsave(&port->lock, flags);
-	status = anakin_in(port, 0x20);
-
-	if (break_state == -1)
-		status |= SETBREAK;
-	else
-		status &= ~SETBREAK;
-
-	anakin_out(port, 0x20, status);
-	spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static int anakin_startup(struct uart_port *port)
-{
-	int retval;
-	unsigned int read,write;
-
-	/*
-	 * Allocate the IRQ
-	 */
-	retval = request_irq(port->irq, anakin_int, SA_INTERRUPT,
-			     "serial_anakin", port);
-	if (retval)
-		return retval;
-
-	/*
-	 * initialise the old status of the modem signals
-	 */
-	port->old_status = 0;
-
-	/*
-	 * Finally, disable IRQ and softIRQs for first byte)
-	 */
-	txenable[port->irq] = 0;
-	read = anakin_in(port, 0x18);
-	write = (read & ~(RTS | DTR | BLOCKRX)) | IRQENABLE;
-	anakin_out(port, 0x18, write);
-
-	return 0;
-}
-
-static void anakin_shutdown(struct uart_port *port)
-{
-	/*
-	 * Free the interrupt
-	 */
-	free_irq(port->irq, port);
-
-	/*
-	 * disable all interrupts, disable the port
-	 */
-	anakin_out(port, 0x18, anakin_in(port, 0x18) & ~IRQENABLE);
-}
-
-static void
-anakin_set_termios(struct uart_port *port, struct termios *termios,
-		   struct termios *old)
-{
-	unsigned long flags;
-	unsigned int baud, quot;
-
-	/*
-	 * We don't support parity, stop bits, or anything other
-	 * than 8 bits, so clear these termios flags.
-	 */
-	termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | CREAD);
-	termios->c_cflag |= CS8;
-
-	/*
-	 * We don't appear to support any error conditions either.
-	 */
-	termios->c_iflag &= ~(INPCK | IGNPAR | IGNBRK | BRKINT);
-
-	/*
-	 * Ask the core to calculate the divisor for us.
-	 */
-	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); 
-	quot = uart_get_divisor(port, baud);
-
-	spin_lock_irqsave(&port->lock, flags);
-
-	uart_update_timeout(port, termios->c_cflag, baud);
-
-	while (!(anakin_in(port, 0x10) & TXEMPTY))
-		barrier();
-
-	anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER)
-			| (quot << 3));
-
-	//parity always set to none
-	anakin_out(port, 0x18, anakin_in(port, 0x18) & ~PARITY);
-	spin_unlock_irqrestore(&port->lock, flags);
-}
-
-static const char *anakin_type(struct port *port)
-{
-	return port->type == PORT_ANAKIN ? "ANAKIN" : NULL;
-}
-
-static struct uart_ops anakin_pops = {
-	.tx_empty	= anakin_tx_empty,
-	.set_mctrl	= anakin_set_mctrl,
-	.get_mctrl	= anakin_get_mctrl,
-	.stop_tx	= anakin_stop_tx,
-	.start_tx	= anakin_start_tx,
-	.stop_rx	= anakin_stop_rx,
-	.enable_ms	= anakin_enable_ms,
-	.break_ctl	= anakin_break_ctl,
-	.startup	= anakin_startup,
-	.shutdown	= anakin_shutdown,
-	.set_termios	= anakin_set_termios,
-	.type		= anakin_type,
-};
-
-static struct uart_port anakin_ports[UART_NR] = {
-	{
-		.base		= IO_BASE + UART0,
-		.irq		= IRQ_UART0,
-		.uartclk	= 3686400,
-		.fifosize	= 0,
-		.ops		= &anakin_pops,
-		.flags		= ASYNC_BOOT_AUTOCONF,
-		.line		= 0,
-	},
-	{
-		.base		= IO_BASE + UART1,
-		.irq		= IRQ_UART1,
-		.uartclk	= 3686400,
-		.fifosize	= 0,
-		.ops		= &anakin_pops,
-		.flags		= ASYNC_BOOT_AUTOCONF,
-		.line		= 1,
-	},
-	{
-		.base		= IO_BASE + UART2,
-		.irq		= IRQ_UART2,
-		.uartclk	= 3686400,
-		.fifosize	= 0,
-		.ops		= &anakin_pops,
-		.flags		= ASYNC_BOOT_AUTOCONF,
-		.line		= 2,
-	},
-	{
-		.base		= IO_BASE + UART3,
-		.irq		= IRQ_UART3,
-		.uartclk	= 3686400,
-		.fifosize	= 0,
-		.ops		= &anakin_pops,
-		.flags		= ASYNC_BOOT_AUTOCONF,
-		.line		= 3,
-	},
-	{
-		.base		= IO_BASE + UART4,
-		.irq		= IRQ_UART4,
-		.uartclk	= 3686400,
-		.fifosize	= 0,
-		.ops		= &anakin_pops,
-		.flags		= ASYNC_BOOT_AUTOCONF,
-		.line		= 4,
-	},
-};
-
-
-#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE
-
-static void
-anakin_console_write(struct console *co, const char *s, unsigned int count)
-{
-	struct uart_port *port = &anakin_ports[co->index];
-	unsigned int flags, status, i;
-
-	/*
-	 *	First save the status then disable the interrupts
-	 */
-	local_irq_save(flags);
-	status = anakin_in(port, 0x18);
-	anakin_out(port, 0x18, status & ~IRQENABLE);
-	local_irq_restore(flags);
-
-	/*
-	 *	Now, do each character
-	 */
-	for (i = 0; i < count; i++, s++) {
-		while (!(anakin_in(port, 0x10) & TXEMPTY))
-			barrier();
-
-		/*
-		 *	Send the character out.
-		 *	If a LF, also do CR...
-		 */
-		anakin_out(port, 0x14, *s);
-		anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
-
-		if (*s == 10) {
-			while (!(anakin_in(port, 0x10) & TXEMPTY))
-				barrier();
-			anakin_out(port, 0x14, 13);
-			anakin_out(port, 0x18, anakin_in(port, 0x18)
-					| SENDREQUEST);
-		}
-	}
-
-	/*
-	 *	Finally, wait for transmitter to become empty
-	 *	and restore the interrupts
-	 */
-	while (!(anakin_in(port, 0x10) & TXEMPTY))
-		barrier();
-
-	if (status & IRQENABLE) {
-		local_irq_save(flags);
- 		anakin_out(port, 0x18, anakin_in(port, 0x18) | IRQENABLE);
-		local_irq_restore(flags);
-	}
-}
-
-/*
- * Read the current UART setup.
- */
-static void __init
-anakin_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
-{
-	int paritycode;
-
-	*baud = GETBAUD (anakin_in(port, 0x10) & PRESCALER);
-	paritycode = GETPARITY(anakin_in(port, 0x18) & PARITY);
-	switch (paritycode) {
-	  case NONEPARITY: *parity = 'n'; break;
-	  case ODDPARITY: *parity = 'o'; break;
-	  case EVENPARITY: *parity = 'e'; break;
-	}
-	*bits = 8;
-}
-
-static int __init
-anakin_console_setup(struct console *co, char *options)
-{
-	struct uart_port *port;
-	int baud = CONFIG_ANAKIN_DEFAULT_BAUDRATE;
-	int bits = 8;
-	int parity = 'n';
-
-	/*
-	 * Check whether an invalid uart number has been specified, and
-	 * if so, search for the first available port that does have
-	 * console support.
-	 */
-	if (co->index >= UART_NR)
-		co->index = 0;
-	port = &anakin_ports[co->index];
-
-	if (options)
-		uart_parse_options(options, &baud, &parity, &bits);
-	else
-		anakin_console_get_options(port, &baud, &parity, &bits);
-
-	return uart_set_options(port, co, baud, parity, bits);
-}
-
-extern struct uart_driver anakin_reg;
-static struct console anakin_console = {
-	.name		= SERIAL_ANAKIN_NAME,
-	.write		= anakin_console_write,
-	.device		= uart_console_device,
-	.setup		= anakin_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-};
-
-static int __init anakin_console_init(void)
-{
-	register_console(&anakin_console);
-	return 0;
-}
-console_initcall(anakin_console_init);
-
-#define ANAKIN_CONSOLE		&anakin_console
-#else
-#define ANAKIN_CONSOLE		NULL
-#endif
-
-static struct uart_driver anakin_reg = {
-	.driver_name		= SERIAL_ANAKIN_NAME,
-	.dev_name		= SERIAL_ANAKIN_NAME,
-	.major			= SERIAL_ANAKIN_MAJOR,
-	.minor			= SERIAL_ANAKIN_MINOR,
-	.nr			= UART_NR,
-	.cons			= ANAKIN_CONSOLE,
-};
-
-static int __init
-anakin_init(void)
-{
-	int ret;
-
-	printk(KERN_INFO "Serial: Anakin driver $Revision: 1.32 $\n");
-
-	ret = uart_register_driver(&anakin_reg);
-	if (ret == 0) {
-		int i;
-
-		for (i = 0; i < UART_NR; i++)
-			uart_add_one_port(&anakin_reg, &anakin_ports[i]);
-	}
-	return ret;
-}
-
-__initcall(anakin_init);
-
-MODULE_DESCRIPTION("Anakin serial driver");
-MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>");
-MODULE_SUPPORTED_DEVICE("ttyAN");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
--- a/drivers/serial/clps711x.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/serial/clps711x.c	Sat Apr  3 19:38:42 2004
@@ -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_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 -Nru a/drivers/serial/mux.c b/drivers/serial/mux.c
--- a/drivers/serial/mux.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/serial/mux.c	Sat Apr  3 19:38:54 2004
@@ -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_AUTHOR("Ryan Bradetich");
 MODULE_DESCRIPTION("Serial MUX driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR);
diff -Nru a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
--- a/drivers/serial/pmac_zilog.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/serial/pmac_zilog.c	Sat Apr  3 19:38:40 2004
@@ -1563,15 +1563,21 @@
 static int pmz_suspend(struct macio_dev *mdev, u32 pm_state)
 {
 	struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
-	struct uart_state *state = pmz_uart_reg.state + uap->port.line;
+	struct uart_state *state;
 	unsigned long flags;
 
-	if (uap == NULL)
+	if (uap == NULL) {
+		printk("HRM... pmz_suspend with NULL uap\n");
 		return 0;
+	}
 
 	if (pm_state == mdev->ofdev.dev.power_state || pm_state < 2)
 		return 0;
 
+	pmz_debug("suspend, switching to state %d\n", pm_state);
+
+	state = pmz_uart_reg.state + uap->port.line;
+
 	down(&pmz_irq_sem);
 	down(&state->sem);
 
@@ -1607,6 +1613,8 @@
 	up(&state->sem);
 	up(&pmz_irq_sem);
 
+	pmz_debug("suspend, switching complete\n");
+
 	mdev->ofdev.dev.power_state = pm_state;
 
 	return 0;
@@ -1616,9 +1624,9 @@
 static int pmz_resume(struct macio_dev *mdev)
 {
 	struct uart_pmac_port *uap = dev_get_drvdata(&mdev->ofdev.dev);
-	struct uart_state *state = pmz_uart_reg.state + uap->port.line;
+	struct uart_state *state;
 	unsigned long flags;
-	int pwr_delay;
+	int pwr_delay = 0;
 
 	if (uap == NULL)
 		return 0;
@@ -1626,6 +1634,10 @@
 	if (mdev->ofdev.dev.power_state == 0)
 		return 0;
 	
+	pmz_debug("resume, switching to state 0\n");
+
+	state = pmz_uart_reg.state + uap->port.line;
+
 	down(&pmz_irq_sem);
 	down(&state->sem);
 
@@ -1658,6 +1670,7 @@
 		enable_irq(uap->port.irq);
 	}
 
+ bail:
 	up(&state->sem);
 	up(&pmz_irq_sem);
 
@@ -1670,7 +1683,8 @@
 		schedule_timeout((pwr_delay * HZ)/1000);
 	}
 
- bail:
+	pmz_debug("resume, switching complete\n");
+
 	mdev->ofdev.dev.power_state = 0;
 
 	return 0;
@@ -1861,9 +1875,6 @@
 	/* Get rid of macio-driver (detach from macio) */
 	macio_unregister_driver(&pmz_driver);
 
-	/* Unregister UART driver */
-	uart_unregister_driver(&pmz_uart_reg);
-
 	for (i = 0; i < pmz_ports_count; i++) {
 		struct uart_pmac_port *uport = &pmz_ports[i];
 		if (uport->node != NULL) {
@@ -1871,6 +1882,8 @@
 			pmz_dispose_port(uport);
 		}
 	}
+	/* Unregister UART driver */
+	uart_unregister_driver(&pmz_uart_reg);
 }
 
 #ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
diff -Nru a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
--- a/drivers/serial/sa1100.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/serial/sa1100.c	Sat Apr  3 19:38:41 2004
@@ -953,3 +953,4 @@
 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 -Nru a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/sh-sci.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,1503 @@
+/*
+ * drivers/serial/sh-sci.c
+ *
+ * SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
+ *
+ *  Copyright (C) 2002, 2003  Paul Mundt
+ *
+ * based off of the old drivers/char/sh-sci.c by:
+ *
+ *   Copyright (C) 1999, 2000  Niibe Yutaka
+ *   Copyright (C) 2000  Sugioka Toshinobu
+ *   Modified to support multiple serial ports. Stuart Menefy (May 2000).
+ *   Modified to support SecureEdge. David McCullough (2002)
+ *   Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
+ *
+ * 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.
+ */
+
+#define DEBUG
+#include <linux/config.h>
+#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/major.h>
+#include <linux/string.h>
+#include <linux/sysrq.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/console.h>
+
+#ifdef CONFIG_CPU_FREQ
+#include <linux/notifier.h>
+#include <linux/cpufreq.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include <linux/generic_serial.h>
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+#include <asm/sh_bios.h>
+#endif
+
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include "sh-sci.h"
+
+#ifdef CONFIG_SH_KGDB
+#include <asm/kgdb.h>
+
+static int kgdb_get_char(struct sci_port *port);
+static void kgdb_put_char(struct sci_port *port, char c);
+static void kgdb_handle_error(struct sci_port *port);
+static struct sci_port *kgdb_sci_port;
+#endif /* CONFIG_SH_KGDB */
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+static struct sci_port *serial_console_port = 0;
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+/* Function prototypes */
+static void sci_stop_tx(struct uart_port *port, unsigned int tty_stop);
+static void sci_start_tx(struct uart_port *port, unsigned int tty_start);
+static void sci_start_rx(struct uart_port *port, unsigned int tty_start);
+static void sci_stop_rx(struct uart_port *port);
+static int sci_request_irq(struct sci_port *port);
+static void sci_free_irq(struct sci_port *port);
+
+static struct sci_port sci_ports[SCI_NPORTS];
+static struct uart_driver sci_uart_driver;
+
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+
+static void handle_error(struct sci_port *port)
+{				/* Clear error flags */
+	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+}
+
+static int get_char(struct sci_port *port)
+{
+	unsigned long flags;
+	unsigned short status;
+	int c;
+
+	local_irq_save(flags);
+        do {
+		status = sci_in(port, SCxSR);
+		if (status & SCxSR_ERRORS(port)) {
+			handle_error(port);
+			continue;
+		}
+	} while (!(status & SCxSR_RDxF(port)));
+	c = sci_in(port, SCxRDR);
+	sci_in(port, SCxSR);            /* Dummy read */
+	sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+	local_irq_restore(flags);
+
+	return c;
+}
+
+/* Taken from sh-stub.c of GDB 4.18 */
+static const char hexchars[] = "0123456789abcdef";
+
+static __inline__ char highhex(int  x)
+{
+	return hexchars[(x >> 4) & 0xf];
+}
+
+static __inline__ char lowhex(int  x)
+{
+	return hexchars[x & 0xf];
+}
+
+#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+
+/*
+ * Send the packet in buffer.  The host gets one chance to read it.
+ * This routine does not wait for a positive acknowledge.
+ */
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+static void put_char(struct uart_port *port, char c)
+{
+	unsigned long flags;
+	unsigned short status;
+
+	local_irq_save(flags);
+
+	do {
+		status = sci_in(port, SCxSR);
+	} while (!(status & SCxSR_TDxE(port)));
+
+	sci_out(port, SCxTDR, c);
+	sci_in(port, SCxSR);            /* Dummy read */
+	sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+
+	local_irq_restore(flags);
+}
+
+static void put_string(struct sci_port *sci_port, const char *buffer, int count)
+{
+	struct uart_port *port = &sci_port->port;
+	const unsigned char *p = buffer;
+	int i;
+
+#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+	int checksum;
+	int usegdb=0;
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+    	/* This call only does a trap the first time it is
+	 * called, and so is safe to do here unconditionally
+	 */
+	usegdb |= sh_bios_in_gdb_mode();
+#endif
+#ifdef CONFIG_SH_KGDB
+	usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port));
+#endif
+
+	if (usegdb) {
+	    /*  $<packet info>#<checksum>. */
+	    do {
+		unsigned char c;
+		put_char(port, '$');
+		put_char(port, 'O'); /* 'O'utput to console */
+		checksum = 'O';
+
+		for (i=0; i<count; i++) { /* Don't use run length encoding */
+			int h, l;
+
+			c = *p++;
+			h = highhex(c);
+			l = lowhex(c);
+			put_char(port, h);
+			put_char(port, l);
+			checksum += h + l;
+		}
+		put_char(port, '#');
+		put_char(port, highhex(checksum));
+		put_char(port, lowhex(checksum));
+	    } while  (get_char(port) != '+');
+	} else
+#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
+	for (i=0; i<count; i++) {
+		if (*p == 10)
+			put_char(port, '\r');
+		put_char(port, *p++);
+	}
+}
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+
+#ifdef CONFIG_SH_KGDB
+
+/* Is the SCI ready, ie is there a char waiting? */
+static int kgdb_is_char_ready(struct sci_port *port)
+{
+        unsigned short status = sci_in(port, SCxSR);
+
+        if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port)))
+                kgdb_handle_error(port);
+
+        return (status & SCxSR_RDxF(port));
+}
+
+/* Write a char */
+static void kgdb_put_char(struct sci_port *port, char c)
+{
+        unsigned short status;
+
+        do
+                status = sci_in(port, SCxSR);
+        while (!(status & SCxSR_TDxE(port)));
+
+        sci_out(port, SCxTDR, c);
+        sci_in(port, SCxSR);    /* Dummy read */
+        sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+}
+
+/* Get a char if there is one, else ret -1 */
+static int kgdb_get_char(struct sci_port *port)
+{
+        int c;
+
+        if (kgdb_is_char_ready(port) == 0)
+                c = -1;
+        else {
+                c = sci_in(port, SCxRDR);
+                sci_in(port, SCxSR);    /* Dummy read */
+                sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+        }
+
+        return c;
+}
+
+/* Called from kgdbstub.c to get a character, i.e. is blocking */
+static int kgdb_sci_getchar(void)
+{
+        volatile int c;
+
+        /* Keep trying to read a character, this could be neater */
+        while ((c = kgdb_get_char(kgdb_sci_port)) < 0);
+
+        return c;
+}
+
+/* Called from kgdbstub.c to put a character, just a wrapper */
+static void kgdb_sci_putchar(int c)
+{
+
+        kgdb_put_char(kgdb_sci_port, c);
+}
+
+/* Clear any errors on the SCI */
+static void kgdb_handle_error(struct sci_port *port)
+{
+        sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));  /* Clear error flags */
+}
+
+/* Breakpoint if there's a break sent on the serial port */
+static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+        struct sci_port *port = ptr;
+        unsigned short status = sci_in(port, SCxSR);
+
+        if (status & SCxSR_BRK(port)) {
+
+                /* Break into the debugger if a break is detected */
+                BREAKPOINT();
+
+                /* Clear */
+                sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+        }
+}
+
+#endif /* CONFIG_SH_KGDB */
+
+#if defined(__H8300S__)
+enum { sci_disable, sci_enable };
+
+static void h8300_sci_enable(struct sci_port* port, unsigned int ctrl)
+{
+	volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL;
+	int ch = (port->base  - SMR0) >> 3;
+	unsigned char mask = 1 << (ch+1);
+
+	if (ctrl == sci_disable) {
+		*mstpcrl |= mask;
+	} else {
+		*mstpcrl &= ~mask;
+	}
+}
+#endif
+
+#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)
+#if defined(__H8300H__) || defined(__H8300S__)
+static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag)
+{
+	int ch = (port->base - SMR0) >> 3;
+
+	/* set DDR regs */
+	H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT);
+	H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT);
+	/* tx mark output*/
+	H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
+}
+#else
+static void sci_init_pins_sci(struct uart_port *port, unsigned int cflag)
+{
+}
+#endif
+#endif
+
+#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
+#if defined(CONFIG_CPU_SH3)
+/* For SH7707, SH7709, SH7709A, SH7729 */
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+	unsigned int fcr_val = 0;
+
+	{
+		unsigned short data;
+
+		/* We need to set SCPCR to enable RTS/CTS */
+		data = ctrl_inw(SCPCR);
+		/* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
+		ctrl_outw(data&0x0fcf, SCPCR);
+	}
+	if (cflag & CRTSCTS)
+		fcr_val |= SCFCR_MCE;
+	else {
+		unsigned short data;
+
+		/* We need to set SCPCR to enable RTS/CTS */
+		data = ctrl_inw(SCPCR);
+		/* Clear out SCP7MD1,0, SCP4MD1,0,
+		   Set SCP6MD1,0 = {01} (output)  */
+		ctrl_outw((data&0x0fcf)|0x1000, SCPCR);
+
+		data = ctrl_inb(SCPDR);
+		/* Set /RTS2 (bit6) = 0 */
+		ctrl_outb(data&0xbf, SCPDR);
+	}
+	sci_out(port, SCFCR, fcr_val);
+}
+
+static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
+{
+	unsigned int fcr_val = 0;
+
+	if (cflag & CRTSCTS)
+		fcr_val |= SCFCR_MCE;
+
+	sci_out(port, SCFCR, fcr_val);
+}
+
+#else
+
+/* For SH7750 */
+static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
+{
+	unsigned int fcr_val = 0;
+
+	if (cflag & CRTSCTS) {
+		fcr_val |= SCFCR_MCE;
+	} else {
+		ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
+	}
+	sci_out(port, SCFCR, fcr_val);
+}
+
+#endif
+#endif /* SCIF_ONLY || SCI_AND_SCIF */
+
+/* ********************************************************************** *
+ *                   the interrupt related routines                       *
+ * ********************************************************************** */
+
+static void sci_transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	unsigned int stopped = uart_tx_stopped(port);
+	unsigned long flags;
+	unsigned short status;
+	unsigned short ctrl;
+	int count, txroom;
+
+	status = sci_in(port, SCxSR);
+	if (!(status & SCxSR_TDxE(port))) {
+		local_irq_save(flags);
+		ctrl = sci_in(port, SCSCR);
+		if (uart_circ_empty(xmit)) {
+			ctrl &= ~SCI_CTRL_FLAGS_TIE;
+		} else {
+			ctrl |= SCI_CTRL_FLAGS_TIE;
+		}
+		sci_out(port, SCSCR, ctrl);
+		local_irq_restore(flags);
+		return;
+	}
+
+	if (port->type == PORT_SCIF) {
+		txroom = 16 - (sci_in(port, SCFDR)>>8);
+	} else {
+		txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
+	}
+
+	count = txroom;
+
+	do {
+		unsigned char c;
+
+		if (port->x_char) {
+			c = port->x_char;
+			port->x_char = 0;
+		} else if (!uart_circ_empty(xmit) && !stopped) {
+			c = xmit->buf[xmit->tail];
+			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		} else {
+			break;
+		}
+
+		sci_out(port, SCxTDR, c);
+
+		port->icount.tx++;
+	} while (--count > 0);
+
+	sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+	if (uart_circ_empty(xmit)) {
+		sci_stop_tx(port, 0);
+	} else {
+		local_irq_save(flags);
+		ctrl = sci_in(port, SCSCR);
+
+		if (port->type == PORT_SCIF) {
+			sci_in(port, SCxSR); /* Dummy read */
+			sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+		}
+
+		ctrl |= SCI_CTRL_FLAGS_TIE;
+		sci_out(port, SCSCR, ctrl);
+		local_irq_restore(flags);
+	}
+}
+
+/* On SH3, SCIF may read end-of-break as a space->mark char */
+#define STEPFN(c)  ({int __c=(c); (((__c-1)|(__c)) == -1); })
+
+static inline void sci_receive_chars(struct uart_port *port,
+				     struct pt_regs *regs)
+{
+	struct tty_struct *tty = port->info->tty;
+	int i, count, copied = 0;
+	unsigned short status;
+
+	status = sci_in(port, SCxSR);
+	if (!(status & SCxSR_RDxF(port)))
+		return;
+
+	while (1) {
+		if (port->type == PORT_SCIF) {
+			count = sci_in(port, SCFDR)&0x001f;
+		} else {
+			count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
+		}
+
+		/* Don't copy more bytes than there is room for in the buffer */
+		if (tty->flip.count + count > TTY_FLIPBUF_SIZE)
+			count = TTY_FLIPBUF_SIZE - tty->flip.count;
+
+		/* If for any reason we can't copy more data, we're done! */
+		if (count == 0)
+			break;
+
+		if (port->type == PORT_SCI) {
+			char c = sci_in(port, SCxRDR);
+                       if(((struct sci_port *)port)->break_flag
+			    || uart_handle_sysrq_char(port, c, regs)) {
+				count = 0;
+			} else {
+			    tty->flip.char_buf_ptr[0] = c;
+			    tty->flip.flag_buf_ptr[0] = TTY_NORMAL;
+			}
+		} else {
+			for (i=0; i<count; i++) {
+				char c = sci_in(port, SCxRDR);
+				status = sci_in(port, SCxSR);
+#if defined(CONFIG_CPU_SH3)
+				/* Skip "chars" during break */
+				if (((struct sci_port *)port)->break_flag) {
+					if ((c == 0) &&
+					    (status & SCxSR_FER(port))) {
+						count--; i--;
+						continue;
+					}
+					/* Nonzero => end-of-break */
+					pr_debug("scif: debounce<%02x>\n", c);
+					((struct sci_port *)port)->break_flag = 0;
+					if (STEPFN(c)) {
+						count--; i--;
+						continue;
+					}
+				}
+#endif /* CONFIG_CPU_SH3 */
+				if (uart_handle_sysrq_char(port, c, regs)) {
+					count--; i--;
+					continue;
+				}
+
+				/* Store data and status */
+				tty->flip.char_buf_ptr[i] = c;
+				if (status&SCxSR_FER(port)) {
+					tty->flip.flag_buf_ptr[i] = TTY_FRAME;
+					pr_debug("sci: frame error\n");
+				} else if (status&SCxSR_PER(port)) {
+					tty->flip.flag_buf_ptr[i] = TTY_PARITY;
+					pr_debug("sci: parity error\n");
+				} else {
+					tty->flip.flag_buf_ptr[i] = TTY_NORMAL;
+				}
+			}
+		}
+
+		sci_in(port, SCxSR); /* dummy read */
+		sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+
+		/* Update the kernel buffer end */
+		tty->flip.count += count;
+		tty->flip.char_buf_ptr += count;
+		tty->flip.flag_buf_ptr += count;
+		copied += count;
+		port->icount.rx += count;
+	}
+
+	if (copied) {
+		/* Tell the rest of the system the news. New characters! */
+		tty_flip_buffer_push(tty);
+	} else {
+		sci_in(port, SCxSR); /* dummy read */
+		sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+	}
+}
+
+#define SCI_BREAK_JIFFIES (HZ/20)
+/* The sci generates interrupts during the break,
+ * 1 per millisecond or so during the break period, for 9600 baud.
+ * So dont bother disabling interrupts.
+ * But dont want more than 1 break event.
+ * Use a kernel timer to periodically poll the rx line until
+ * the break is finished.
+ */
+static void sci_schedule_break_timer(struct sci_port *port)
+{
+	port->break_timer.expires = jiffies + SCI_BREAK_JIFFIES;
+	add_timer(&port->break_timer);
+}
+/* Ensure that two consecutive samples find the break over. */
+static void sci_break_timer(unsigned long data)
+{
+    struct sci_port * port = (struct sci_port *)data;
+	if(sci_rxd_in(&port->port) == 0) {
+		port->break_flag = 1;
+	    sci_schedule_break_timer(port);
+	} else if(port->break_flag == 1){
+		/* break is over. */
+		port->break_flag = 2;
+	    sci_schedule_break_timer(port);
+	} else port->break_flag = 0;
+}
+
+static inline int sci_handle_errors(struct uart_port *port)
+{
+	int copied = 0;
+	unsigned short status = sci_in(port, SCxSR);
+	struct tty_struct *tty = port->info->tty;
+
+	if (status&SCxSR_ORER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
+		/* overrun error */
+		copied++;
+		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+		pr_debug("sci: overrun error\n");
+	}
+
+	if (status&SCxSR_FER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
+		if (sci_rxd_in(port) == 0) {
+			/* Notify of BREAK */
+			struct sci_port * sci_port = (struct sci_port *)port;
+                       if(!sci_port->break_flag) {
+	                        sci_port->break_flag = 1;
+                               sci_schedule_break_timer((struct sci_port *)port);
+				/* Do sysrq handling. */
+				if(uart_handle_break(port)) {
+					return 0;
+				}
+			        pr_debug("sci: BREAK detected\n");
+			        copied++;
+			        *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+                       }
+		}
+		else {
+			/* frame error */
+			copied++;
+			*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+			pr_debug("sci: frame error\n");
+		}
+	}
+
+	if (status&SCxSR_PER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
+		/* parity error */
+		copied++;
+		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+		pr_debug("sci: parity error\n");
+	}
+
+	if (copied) {
+		tty->flip.count += copied;
+		tty_flip_buffer_push(tty);
+	}
+
+	return copied;
+}
+
+static inline int sci_handle_breaks(struct uart_port *port)
+{
+	int copied = 0;
+	unsigned short status = sci_in(port, SCxSR);
+	struct tty_struct *tty = port->info->tty;
+	struct sci_port *s = &sci_ports[port->line];
+
+	if (!s->break_flag && status & SCxSR_BRK(port) &&
+	    tty->flip.count < TTY_FLIPBUF_SIZE) {
+#if defined(CONFIG_CPU_SH3)
+		/* Debounce break */
+		s->break_flag = 1;
+#endif
+		/* Notify of BREAK */
+		copied++;
+		*tty->flip.flag_buf_ptr++ = TTY_BREAK;
+		pr_debug("sci: BREAK detected\n");
+	}
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_ST40STB1) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7760)
+	/* XXX: Handle SCIF overrun error */
+	if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
+		sci_out(port, SCLSR, 0);
+		if(tty->flip.count<TTY_FLIPBUF_SIZE) {
+			copied++;
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+			pr_debug("sci: overrun error\n");
+		}
+	}
+#endif
+
+	if (copied) {
+		tty->flip.count += copied;
+		tty_flip_buffer_push(tty);
+	}
+
+	return copied;
+}
+
+static irqreturn_t sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	struct uart_port *port = ptr;
+
+	/* I think sci_receive_chars has to be called irrespective
+	 * of whether the I_IXOFF is set, otherwise, how is the interrupt
+	 * to be disabled?
+	 */
+	sci_receive_chars(port, regs);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	struct uart_port *port = ptr;
+
+	sci_transmit_chars(port);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	struct uart_port *port = ptr;
+
+	/* Handle errors */
+	if (port->type == PORT_SCI) {
+		if (sci_handle_errors(port)) {
+			/* discard character in rx buffer */
+			sci_in(port, SCxSR);
+			sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+		}
+	} else {
+		sci_rx_interrupt(irq, ptr, regs);
+	}
+
+	sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+
+	/* Kick the transmission */
+	sci_tx_interrupt(irq, ptr, regs);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+	struct uart_port *port = ptr;
+
+	/* Handle BREAKs */
+	sci_handle_breaks(port);
+	sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+
+	return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_CPU_FREQ
+/*
+ * Here we define a transistion notifier so that we can update all of our
+ * ports' baud rate when the peripheral clock changes.
+ */
+static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p)
+{
+	struct cpufreq_freqs *freqs = p;
+	int i;
+
+	if (phase == CPUFREQ_POSTCHANGE) {
+		for (i = 0; i < SCI_NPORTS; i++) {
+			struct uart_port *port = &sci_ports[i];
+
+			/*
+			 * Update the uartclk per-port if frequency has
+			 * changed, since it will no longer necessarily be
+			 * consistent with the old frequency.
+			 *
+			 * Really we want to be able to do something like
+			 * uart_change_speed() or something along those lines
+			 * here to implicitly reset the per-port baud rate..
+			 *
+			 * Clean this up later..
+			 */
+			port->uartclk = current_cpu_data.module_clock * 16;
+		}
+
+		printk("%s: got a postchange notification for cpu %d (old %d, new %d)\n",
+				__FUNCTION__, freqs->cpu, freqs->old, freqs->new);
+	}
+
+	return NOTIFY_OK;
+}
+
+static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 };
+#endif /* CONFIG_CPU_FREQ */
+
+static int sci_request_irq(struct sci_port *port)
+{
+	int i;
+	irqreturn_t (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = {
+		sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
+		sci_br_interrupt,
+	};
+	const char *desc[] = { "SCI Receive Error", "SCI Receive Data Full",
+			       "SCI Transmit Data Empty", "SCI Break" };
+
+	for (i = 0; i < ARRAY_SIZE(handlers); i++) {
+		if (!port->irqs[i])
+			continue;
+		if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
+				desc[i], port)) {
+			printk(KERN_ERR "sci: Cannot allocate irq.\n");
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static void sci_free_irq(struct sci_port *port)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(port->irqs); i++) {
+		if (!port->irqs[i])
+			continue;
+
+		free_irq(port->irqs[i], port);
+	}
+}
+
+static unsigned int sci_tx_empty(struct uart_port *port)
+{
+	/* Can't detect */
+	return TIOCSER_TEMT;
+}
+
+static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	/* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
+	/* We use SCIF's hardware for CTS/RTS, so don't need any for that. */
+	/* If you have signals for DTR and DCD, please implement here. */
+}
+
+static unsigned int sci_get_mctrl(struct uart_port *port)
+{
+	/* This routine is used for geting signals of: DTR, DCD, DSR, RI,
+	   and CTS/RTS */
+
+	return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
+}
+
+static void sci_start_tx(struct uart_port *port, unsigned int tty_start)
+{
+	struct sci_port *s = &sci_ports[port->line];
+
+	disable_irq(s->irqs[SCIx_TXI_IRQ]);
+	sci_transmit_chars(port);
+	enable_irq(s->irqs[SCIx_TXI_IRQ]);
+}
+
+static void sci_stop_tx(struct uart_port *port, unsigned int tty_stop)
+{
+	unsigned long flags;
+	unsigned short ctrl;
+
+	/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
+	local_irq_save(flags);
+	ctrl = sci_in(port, SCSCR);
+	ctrl &= ~SCI_CTRL_FLAGS_TIE;
+	sci_out(port, SCSCR, ctrl);
+	local_irq_restore(flags);
+}
+
+static void sci_start_rx(struct uart_port *port, unsigned int tty_start)
+{
+	unsigned long flags;
+	unsigned short ctrl;
+
+	/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
+	local_irq_save(flags);
+	ctrl = sci_in(port, SCSCR);
+	ctrl |= SCI_CTRL_FLAGS_RIE;
+	sci_out(port, SCSCR, ctrl);
+	local_irq_restore(flags);
+}
+
+static void sci_stop_rx(struct uart_port *port)
+{
+	unsigned long flags;
+	unsigned short ctrl;
+
+	/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
+	local_irq_save(flags);
+	ctrl = sci_in(port, SCSCR);
+	ctrl &= ~SCI_CTRL_FLAGS_RIE;
+	sci_out(port, SCSCR, ctrl);
+	local_irq_restore(flags);
+}
+
+static void sci_enable_ms(struct uart_port *port)
+{
+	/* Nothing here yet .. */
+}
+
+static void sci_break_ctl(struct uart_port *port, int break_state)
+{
+	/* Nothing here yet .. */
+}
+
+static int sci_startup(struct uart_port *port)
+{
+	struct sci_port *s = &sci_ports[port->line];
+
+	sci_request_irq(s);
+	sci_start_tx(port, 1);
+	sci_start_rx(port, 1);
+
+#if defined(__H8300S__)
+	h8300_sci_enable(port, sci_enable);
+#endif
+
+	return 0;
+}
+
+static void sci_shutdown(struct uart_port *port)
+{
+	struct sci_port *s = &sci_ports[port->line];
+
+	sci_stop_rx(port);
+	sci_stop_tx(port, 1);
+	sci_free_irq(s);
+
+#if defined(__H8300S__)
+	h8300_sci_enable(port, sci_disable);
+#endif
+}
+
+static void sci_set_termios(struct uart_port *port, struct termios *termios,
+			    struct termios *old)
+{
+	struct sci_port *s = &sci_ports[port->line];
+	unsigned int status, baud, smr_val;
+	unsigned long flags;
+	int t;
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	do {
+		status = sci_in(port, SCxSR);
+	} while (!(status & SCxSR_TEND(port)));
+
+	sci_out(port, SCSCR, 0x00);	/* TE=0, RE=0, CKE1=0 */
+
+	if (port->type == PORT_SCIF) {
+		sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+	}
+
+	smr_val = sci_in(port, SCSMR) & 3;
+	if ((termios->c_cflag & CSIZE) == CS7)
+		smr_val |= 0x40;
+	if (termios->c_cflag & PARENB)
+		smr_val |= 0x20;
+	if (termios->c_cflag & PARODD)
+		smr_val |= 0x30;
+	if (termios->c_cflag & CSTOPB)
+		smr_val |= 0x08;
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	sci_out(port, SCSMR, smr_val);
+
+	switch (baud) {
+		case 0:		t = -1;		break;
+		case 2400:	t = BPS_2400;	break;
+		case 4800:	t = BPS_4800;	break;
+		case 9600:	t = BPS_9600;	break;
+		case 19200:	t = BPS_19200;	break;
+		case 38400:	t = BPS_38400;	break;
+		case 57600:	t = BPS_57600;	break;
+		case 115200:	t = BPS_115200;	break;
+		default:	t = BPS_115200; break;
+	}
+
+	if (t > 0) {
+		if(t >= 256) {
+			sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
+			t >>= 2;
+		} else {
+			sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
+		}
+		sci_out(port, SCBRR, t);
+		udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
+	}
+
+	s->init_pins(port, termios->c_cflag);
+	sci_out(port, SCSCR, SCSCR_INIT(port));
+
+	if ((termios->c_cflag & CREAD) != 0)
+              sci_start_rx(port,0);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *sci_type(struct uart_port *port)
+{
+	switch (port->type) {
+		case PORT_SCI:	return "sci";
+		case PORT_SCIF:	return "scif";
+		case PORT_IRDA: return "irda";
+	}
+
+	return 0;
+}
+
+static void sci_release_port(struct uart_port *port)
+{
+	/* Nothing here yet .. */
+}
+
+static int sci_request_port(struct uart_port *port)
+{
+	/* Nothing here yet .. */
+	return 0;
+}
+
+static void sci_config_port(struct uart_port *port, int flags)
+{
+	struct sci_port *s = &sci_ports[port->line];
+
+	port->type = s->type;
+}
+
+static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	struct sci_port *s = &sci_ports[port->line];
+
+	if (ser->irq != s->irqs[SCIx_TXI_IRQ] || ser->irq > NR_IRQS)
+		return -EINVAL;
+	if (ser->baud_base < 2400)
+		/* No paper tape reader for Mitch.. */
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct uart_ops sci_uart_ops = {
+	.tx_empty	= sci_tx_empty,
+	.set_mctrl	= sci_set_mctrl,
+	.get_mctrl	= sci_get_mctrl,
+	.start_tx	= sci_start_tx,
+	.stop_tx	= sci_stop_tx,
+	.stop_rx	= sci_stop_rx,
+	.enable_ms	= sci_enable_ms,
+	.break_ctl	= sci_break_ctl,
+	.startup	= sci_startup,
+	.shutdown	= sci_shutdown,
+	.set_termios	= sci_set_termios,
+	.type		= sci_type,
+	.release_port	= sci_release_port,
+	.request_port	= sci_request_port,
+	.config_port	= sci_config_port,
+	.verify_port	= sci_verify_port,
+};
+
+static struct sci_port sci_ports[SCI_NPORTS] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7708)
+	{
+		.port	= {
+			.membase	= (void *)0xfffffe80,
+			.mapbase	= 0xfffffe80,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 25,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+		.type		= PORT_SCI,
+		.irqs		= SCI_IRQS,
+		.init_pins	= sci_init_pins_sci,
+	},
+#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+	{
+		.port	= {
+			.membase	= (void *)0xfffffe80,
+			.mapbase	= 0xfffffe80,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 25,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+		.type		= PORT_SCI,
+		.irqs		= SCI_IRQS,
+		.init_pins	= sci_init_pins_sci,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0xa4000150,
+			.mapbase	= 0xa4000150,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 59,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+		.type		= PORT_SCIF,
+		.irqs		= SH3_SCIF_IRQS,
+		.init_pins	= sci_init_pins_scif,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0xa4000140,
+			.mapbase	= 0xa4000140,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 55,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 2,
+		},
+		.type		= PORT_IRDA,
+		.irqs		= SH3_IRDA_IRQS,
+		.init_pins	= sci_init_pins_irda,
+	}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
+	{
+		.port	= {
+			.membase	= (void *)0xffe00000,
+			.mapbase	= 0xffe00000,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 25,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+		.type		= PORT_SCI,
+		.irqs		= SCI_IRQS,
+		.init_pins	= sci_init_pins_sci,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0xffe80000,
+			.mapbase	= 0xffe80000,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 43,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+		.type		= PORT_SCIF,
+		.irqs		= SH4_SCIF_IRQS,
+		.init_pins	= sci_init_pins_scif,
+	},
+#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+	{
+		.port	= {
+			.membase	= (void *)0xfe600000,
+			.mapbase	= 0xfe600000,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 55,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+		.type		= PORT_SCIF,
+		.irqs		= SH7760_SCIF0_IRQS,
+		.init_pins	= sci_init_pins_scif,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0xfe610000,
+			.mapbase	= 0xfe610000,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 75,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+		.type		= PORT_SCIF,
+		.irqs		= SH7760_SCIF1_IRQS,
+		.init_pins	= sci_init_pins_scif,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0xfe620000,
+			.mapbase	= 0xfe620000,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 79,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 2,
+		},
+		.type		= PORT_SCIF,
+		.irqs		= SH7760_SCIF2_IRQS,
+		.init_pins	= sci_init_pins_scif,
+	},
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+	{
+		.port	= {
+			.membase	= (void *)0xffe00000,
+			.mapbase	= 0xffe00000,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 26,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+		.type		= PORT_SCIF,
+		.irqs		= STB1_SCIF1_IRQS,
+		.init_pins	= sci_init_pins_scif,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0xffe80000,
+			.mapbase	= 0xffe80000,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 43,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+		.type		= PORT_SCIF,
+		.irqs		= SH4_SCIF_IRQS,
+		.init_pins	= sci_init_pins_scif,
+	},
+#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
+	{
+		.port	= {
+			.membase	= (void *)0x00ffffb0,
+			.mapbase	= 0x00ffffb0,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 54,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+		.type		= PORT_SCI,
+		.irqs		= H8300H_SCI_IRQS0,
+		.init_pins	= sci_init_pins_sci,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0x00ffffb8,
+			.mapbase	= 0x00ffffb8,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 58,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+		.type		= PORT_SCI,
+		.irqs		= H8300H_SCI_IRQS1,
+		.init_pins	= sci_init_pins_sci,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0x00ffffc0,
+			.mapbase	= 0x00ffffc0,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 62,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 2,
+		},
+		.type		= PORT_SCI,
+		.irqs		= H8300H_SCI_IRQS2,
+		.init_pins	= sci_init_pins_sci,
+	},
+#elif defined(CONFIG_H8S2678)
+	{
+		.port	= {
+			.membase	= (void *)0x00ffff78,
+			.mapbase	= 0x00ffff78,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 90,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 0,
+		},
+		.type		= PORT_SCI,
+		.irqs		= H8S_SCI_IRQS0,
+		.init_pins	= sci_init_pins_sci,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0x00ffff80,
+			.mapbase	= 0x00ffff80,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 94,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 1,
+		},
+		.type		= PORT_SCI,
+		.irqs		= H8S_IRQS1,
+		.init_pins	= sci_init_pins_sci,
+	},
+	{
+		.port	= {
+			.membase	= (void *)0x00ffff88,
+			.mapbase	= 0x00ffff88,
+			.iotype		= SERIAL_IO_MEM,
+			.irq		= 98,
+			.ops		= &sci_uart_ops,
+			.flags		= ASYNC_BOOT_AUTOCONF,
+			.line		= 2,
+		},
+		.type		= PORT_SCI,
+		.irqs		= H8S_IRQS2,
+		.init_pins	= sci_init_pins_sci,
+	},
+#else
+#error "CPU subtype not defined"
+#endif
+};
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ */
+static void serial_console_write(struct console *co, const char *s,
+				 unsigned count)
+{
+	put_string(serial_console_port, s, count);
+}
+
+static int __init serial_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= SCI_NPORTS)
+		co->index = 0;
+
+	serial_console_port = &sci_ports[co->index];
+	port = &serial_console_port->port;
+	port->type = serial_console_port->type;
+
+	/*
+	 * We need to set the initial uartclk here, since otherwise it will
+	 * only ever be setup at sci_init() time.
+	 */
+	port->uartclk = current_cpu_data.module_clock * 16;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console serial_console = {
+	.name		= "ttySC",
+	.device		= uart_console_device,
+	.write		= serial_console_write,
+	.setup		= serial_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &sci_uart_driver,
+};
+
+static int __init sci_console_init(void)
+{
+#ifdef CONFIG_SH_EARLY_PRINTK
+	extern void sh_console_unregister(void);
+
+	/*
+	 * Now that the real console is available, unregister the one we
+	 * used while first booting.
+	 */
+	sh_console_unregister();
+#endif
+
+	register_console(&serial_console);
+
+	return 0;
+}
+
+console_initcall(sci_console_init);
+#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+
+#ifdef CONFIG_SH_KGDB
+/*
+ * FIXME: Most of this can go away.. at the moment, we rely on
+ * arch/sh/kernel/setup.c to do the command line parsing for kgdb, though
+ * most of that can easily be done here instead.
+ *
+ * For the time being, just accept the values that were parsed earlier..
+ */
+static void __init kgdb_console_get_options(struct uart_port *port, int *baud,
+					    int *parity, int *bits)
+{
+	*baud = kgdb_baud;
+	*parity = tolower(kgdb_parity);
+	*bits = kgdb_bits - '0';
+}
+
+/*
+ * The naming here is somewhat misleading, since kgdb_console_setup() takes
+ * care of the early-on initialization for kgdb, regardless of whether we
+ * actually use kgdb as a console or not.
+ *
+ * On the plus side, this lets us kill off the old kgdb_sci_setup() nonsense.
+ */
+int __init kgdb_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port = &sci_ports[kgdb_portnum].port;
+	int baud = 38400;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index >= SCI_NPORTS || co->index != kgdb_portnum)
+		co->index = kgdb_portnum;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		kgdb_console_get_options(port, &baud, &parity, &bits);
+
+	kgdb_getchar = kgdb_sci_getchar;
+	kgdb_putchar = kgdb_sci_putchar;
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+#endif /* CONFIG_SH_KGDB */
+
+#ifdef CONFIG_SH_KGDB_CONSOLE
+static struct console kgdb_console = {
+        .name		= "ttySC",
+        .write		= kgdb_console_write,
+        .setup		= kgdb_console_setup,
+        .flags		= CON_PRINTBUFFER | CON_ENABLED,
+        .index		= -1,
+	.data		= &sci_uart_driver,
+};
+
+/* Register the KGDB console so we get messages (d'oh!) */
+static int __init kgdb_console_init(void)
+{
+        register_console(&kgdb_console);
+
+	return 0;
+}
+
+console_initcall(kgdb_console_init);
+#endif /* CONFIG_SH_KGDB_CONSOLE */
+
+#if defined(CONFIG_SH_KGDB_CONSOLE)
+#define SCI_CONSOLE	&kgdb_console
+#elif defined(CONFIG_SERIAL_SH_SCI_CONSOLE)
+#define SCI_CONSOLE	&serial_console
+#else
+#define SCI_CONSOLE 	0
+#endif
+
+static char banner[] __initdata =
+	KERN_INFO "SuperH SCI(F) driver initialized\n";
+
+static struct uart_driver sci_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "sci",
+#ifdef CONFIG_DEVFS_FS
+	.devfs_name	= "ttsc/",
+#endif
+	.dev_name	= "ttySC",
+	.major		= SCI_MAJOR,
+	.minor		= SCI_MINOR_START,
+	.nr		= SCI_NPORTS,
+	.cons		= SCI_CONSOLE,
+};
+
+static int __init sci_init(void)
+{
+	int chan, ret;
+
+	printk("%s", banner);
+
+	ret = uart_register_driver(&sci_uart_driver);
+	if (ret == 0) {
+		for (chan = 0; chan < SCI_NPORTS; chan++) {
+			struct sci_port *sciport = &sci_ports[chan];
+
+			sciport->port.uartclk = (current_cpu_data.module_clock * 16);
+			uart_add_one_port(&sci_uart_driver, &sciport->port);
+			sciport->break_timer.data = (unsigned long)sciport;
+			sciport->break_timer.function = sci_break_timer;
+			init_timer(&sciport->break_timer);
+		}
+	}
+
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
+	printk("sci: CPU frequency notifier registered\n");
+#endif
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+	sh_bios_gdb_detach();
+#endif
+
+	return ret;
+}
+
+static void __exit sci_exit(void)
+{
+	int chan;
+
+	for (chan = 0; chan < SCI_NPORTS; chan++)
+		uart_remove_one_port(&sci_uart_driver, &sci_ports[chan].port);
+
+	uart_unregister_driver(&sci_uart_driver);
+}
+
+module_init(sci_init);
+module_exit(sci_exit);
+
diff -Nru a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/sh-sci.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,435 @@
+/* $Id: sh-sci.h,v 1.4 2004/02/19 16:43:56 lethal Exp $
+ *
+ *  linux/drivers/serial/sh-sci.h
+ *
+ *  SuperH on-chip serial module support.  (SCI with no FIFO / with FIFO)
+ *  Copyright (C) 1999, 2000  Niibe Yutaka
+ *  Copyright (C) 2000  Greg Banks
+ *  Copyright (C) 2002, 2003  Paul Mundt
+ *  Modified to support multiple serial ports. Stuart Menefy (May 2000).
+ *  Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
+ */
+#include <linux/config.h>
+#include <linux/serial_core.h>
+
+#if defined(__H8300H__) || defined(__H8300S__)
+#include <asm/gpio.h>
+#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+#include <asm/regs306x.h>
+#endif
+#if defined(CONFIG_H8S2678)
+#include <asm/regs267x.h>
+#endif
+#endif
+
+/* Offsets into the sci_port->irqs array */
+#define SCIx_ERI_IRQ 0
+#define SCIx_RXI_IRQ 1
+#define SCIx_TXI_IRQ 2
+
+/*                     ERI, RXI, TXI, BRI */
+#define SCI_IRQS      { 23,  24,  25,   0 }
+#define SH3_SCIF_IRQS { 56,  57,  59,  58 }
+#define SH3_IRDA_IRQS { 52,  53,  55,  54 }
+#define SH4_SCIF_IRQS { 40,  41,  43,  42 }
+#define STB1_SCIF1_IRQS {23, 24,  26,  25 }
+#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 }
+#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 }
+#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 }
+#define H8300H_SCI_IRQS0 {52, 53, 54,   0 }
+#define H8300H_SCI_IRQS1 {56, 57, 58,   0 }
+#define H8300H_SCI_IRQS2 {60, 61, 62,   0 }
+#define H8S_SCI_IRQS0 {88, 89, 90,   0 }
+#define H8S_SCI_IRQS1 {92, 93, 94,   0 }
+#define H8S_SCI_IRQS2 {96, 97, 98,   0 }
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7708)
+# define SCI_NPORTS 1
+# define SCSPTR 0xffffff7c /* 8 bit */
+# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+# define SCI_NPORTS 3
+# define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
+# define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
+# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_AND_SCIF
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
+# define SCI_NPORTS 2
+# define SCSPTR1 0xffe0001c /* 8  bit SCI */
+# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
+	0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
+	0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
+# define SCI_AND_SCIF
+#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+# define SCI_NPORTS 3
+# define SCSPTR0 0xfe600000 /* 16 bit SCIF */
+# define SCSPTR1 0xfe610000 /* 16 bit SCIF */
+# define SCSPTR2 0xfe620000 /* 16 bit SCIF */
+# define SCIF_ORDER 0x0001  /* overrun error bit */
+# define SCSCR_INIT(port)          0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+# define SCI_NPORTS 2
+# define SCSPTR1 0xffe00020 /* 16 bit SCIF */
+# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001   /* overrun error bit */
+# define SCSCR_INIT(port)          0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
+#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
+# define SCI_NPORTS 3
+# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_ONLY
+# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+#elif defined(CONFIG_H8S2678)
+# define SCI_NPORTS 3
+# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_ONLY
+# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+#else
+# error CPU subtype not defined
+#endif
+
+/* SCSCR */
+#define SCI_CTRL_FLAGS_TIE  0x80 /* all */
+#define SCI_CTRL_FLAGS_RIE  0x40 /* all */
+#define SCI_CTRL_FLAGS_TE   0x20 /* all */
+#define SCI_CTRL_FLAGS_RE   0x10 /* all */
+/*      SCI_CTRL_FLAGS_REIE 0x08  * 7750 SCIF */
+/*      SCI_CTRL_FLAGS_MPIE 0x08  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_CTRL_FLAGS_TEIE 0x04  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_CTRL_FLAGS_CKE1 0x02  * all */
+/*      SCI_CTRL_FLAGS_CKE0 0x01  * 7707 SCI/SCIF, 7708 SCI, 7709 SCI/SCIF, 7750 SCI */
+
+/* SCxSR SCI */
+#define SCI_TDRE  0x80 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_RDRF  0x40 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_ORER  0x20 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_FER   0x10 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_PER   0x08 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_TEND  0x04 /* 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_MPB   0x02  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+/*      SCI_MPBT  0x01  * 7707 SCI, 7708 SCI, 7709 SCI, 7750 SCI */
+
+#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
+
+/* SCxSR SCIF */
+#define SCIF_ER    0x0080 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_TEND  0x0040 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_TDFE  0x0020 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_BRK   0x0010 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_FER   0x0008 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_PER   0x0004 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_RDF   0x0002 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */
+#define SCIF_DR    0x0001 /* 7707 SCIF, 7709 SCIF, 7750 SCIF */
+
+#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
+
+#if defined(SCI_ONLY)
+# define SCxSR_TEND(port)		SCI_TEND
+# define SCxSR_ERRORS(port)		SCI_ERRORS
+# define SCxSR_RDxF(port)               SCI_RDRF
+# define SCxSR_TDxE(port)               SCI_TDRE
+# define SCxSR_ORER(port)		SCI_ORER
+# define SCxSR_FER(port)		SCI_FER
+# define SCxSR_PER(port)		SCI_PER
+# define SCxSR_BRK(port)		0x00
+# define SCxSR_RDxF_CLEAR(port)		0xbc
+# define SCxSR_ERROR_CLEAR(port)	0xc4
+# define SCxSR_TDxE_CLEAR(port)		0x78
+# define SCxSR_BREAK_CLEAR(port)   	0xc4
+#elif defined(SCIF_ONLY)
+# define SCxSR_TEND(port)		SCIF_TEND
+# define SCxSR_ERRORS(port)		SCIF_ERRORS
+# define SCxSR_RDxF(port)               SCIF_RDF
+# define SCxSR_TDxE(port)               SCIF_TDFE
+# define SCxSR_ORER(port)		0x0000
+# define SCxSR_FER(port)		SCIF_FER
+# define SCxSR_PER(port)		SCIF_PER
+# define SCxSR_BRK(port)		SCIF_BRK
+# define SCxSR_RDxF_CLEAR(port)		0x00fc
+# define SCxSR_ERROR_CLEAR(port)	0x0073
+# define SCxSR_TDxE_CLEAR(port)		0x00df
+# define SCxSR_BREAK_CLEAR(port)   	0x00e3
+#else
+# define SCxSR_TEND(port)	 (((port)->type == PORT_SCI) ? SCI_TEND   : SCIF_TEND)
+# define SCxSR_ERRORS(port)	 (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
+# define SCxSR_RDxF(port)        (((port)->type == PORT_SCI) ? SCI_RDRF   : SCIF_RDF)
+# define SCxSR_TDxE(port)        (((port)->type == PORT_SCI) ? SCI_TDRE   : SCIF_TDFE)
+# define SCxSR_ORER(port)        (((port)->type == PORT_SCI) ? SCI_ORER   : 0x0000)
+# define SCxSR_FER(port)         (((port)->type == PORT_SCI) ? SCI_FER    : SCIF_FER)
+# define SCxSR_PER(port)         (((port)->type == PORT_SCI) ? SCI_PER    : SCIF_PER)
+# define SCxSR_BRK(port)         (((port)->type == PORT_SCI) ? 0x00       : SCIF_BRK)
+# define SCxSR_RDxF_CLEAR(port)	 (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
+# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
+# define SCxSR_TDxE_CLEAR(port)  (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
+# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
+#endif
+
+/* SCFCR */
+#define SCFCR_RFRST 0x0002
+#define SCFCR_TFRST 0x0004
+#define SCFCR_MCE   0x0008
+
+#define SCI_MAJOR		204
+#define SCI_MINOR_START		8
+
+/* Generic serial flags */
+#define SCI_RX_THROTTLE		0x0000001
+
+#define SCI_MAGIC 0xbabeface
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define SCI_EVENT_WRITE_WAKEUP	0
+
+struct sci_port {
+	struct uart_port port;
+	int type;
+	unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */
+	void (*init_pins)(struct uart_port *port, unsigned int cflag);
+	int break_flag;
+	struct timer_list break_timer;
+};
+
+#define SCI_IN(size, offset)					\
+  unsigned int addr = port->mapbase + (offset);			\
+  if ((size) == 8) { 						\
+    return ctrl_inb(addr);					\
+  } else {					 		\
+    return ctrl_inw(addr);					\
+  }
+#define SCI_OUT(size, offset, value)				\
+  unsigned int addr = port->mapbase + (offset);			\
+  if ((size) == 8) { 						\
+    ctrl_outb(value, addr);					\
+  } else {							\
+    ctrl_outw(value, addr);					\
+  }
+
+#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
+  static inline unsigned int sci_##name##_in(struct uart_port *port)	\
+  {									\
+    if (port->type == PORT_SCI) { 					\
+      SCI_IN(sci_size, sci_offset)					\
+    } else {								\
+      SCI_IN(scif_size, scif_offset);		 			\
+    }									\
+  }									\
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {									\
+    if (port->type == PORT_SCI) {					\
+      SCI_OUT(sci_size, sci_offset, value)				\
+    } else {								\
+      SCI_OUT(scif_size, scif_offset, value);				\
+    }									\
+  }
+
+#define CPU_SCIF_FNS(name, scif_offset, scif_size)				\
+  static inline unsigned int sci_##name##_in(struct uart_port *port)	\
+  {									\
+    SCI_IN(scif_size, scif_offset);		 			\
+  }									\
+  static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
+  {									\
+    SCI_OUT(scif_size, scif_offset, value);				\
+  }
+
+#define CPU_SCI_FNS(name, sci_offset, sci_size)				\
+  static inline unsigned int sci_##name##_in(struct sci_port* port)	\
+  {									\
+    SCI_IN(sci_size, sci_offset);		 			\
+  }									\
+  static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \
+  {									\
+    SCI_OUT(sci_size, sci_offset, value);				\
+  }
+
+#ifdef CONFIG_CPU_SH3
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+		 sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                 h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
+#elif defined(__H8300H__) || defined(__H8300S__)
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+		 sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+                 h8_sci_offset, h8_sci_size) \
+  CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size)
+#else
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+		 sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+		 h8_sci_offset, h8_sci_size) \
+  CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#endif
+
+/*      reg      SCI/SH3   SCI/SH4  SCIF/SH3   SCIF/SH4  SCI/H8*/
+/*      name     off  sz   off  sz   off  sz   off  sz   off  sz*/
+SCIx_FNS(SCSMR,  0x00,  8, 0x00,  8, 0x00,  8, 0x00, 16, 0x00,  8)
+SCIx_FNS(SCBRR,  0x02,  8, 0x04,  8, 0x02,  8, 0x04,  8, 0x01,  8)
+SCIx_FNS(SCSCR,  0x04,  8, 0x08,  8, 0x04,  8, 0x08, 16, 0x02,  8)
+SCIx_FNS(SCxTDR, 0x06,  8, 0x0c,  8, 0x06,  8, 0x0C,  8, 0x03,  8)
+SCIx_FNS(SCxSR,  0x08,  8, 0x10,  8, 0x08, 16, 0x10, 16, 0x04,  8)
+SCIx_FNS(SCxRDR, 0x0a,  8, 0x14,  8, 0x0A,  8, 0x14,  8, 0x05,  8)
+SCIF_FNS(SCFCR,                      0x0c,  8, 0x18, 16)
+SCIF_FNS(SCFDR,                      0x0e, 16, 0x1C, 16)
+SCIF_FNS(SCLSR,                         0,  0, 0x24, 16)
+
+#define sci_in(port, reg) sci_##reg##_in(port)
+#define sci_out(port, reg, value) sci_##reg##_out(port, value)
+
+/* H8/300 series SCI pins assignment */
+#if defined(__H8300H__) || defined(__H8300S__)
+static const struct __attribute__((packed)) {
+	int port;             /* GPIO port no */
+	unsigned short rx,tx; /* GPIO bit no */
+} h8300_sci_pins[] = {
+#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+	{    /* SCI0 */
+		.port = H8300_GPIO_P9,
+		.rx   = H8300_GPIO_B2,
+		.tx   = H8300_GPIO_B0,
+	},
+	{    /* SCI1 */
+		.port = H8300_GPIO_P9,
+		.rx   = H8300_GPIO_B3,
+		.tx   = H8300_GPIO_B1,
+	},
+	{    /* SCI2 */
+		.port = H8300_GPIO_PB,
+		.rx   = H8300_GPIO_B7,
+		.tx   = H8300_GPIO_B6,
+	}
+#elif defined(CONFIG_H8S2678)
+	{    /* SCI0 */
+		.port = H8300_GPIO_P3,
+		.rx   = H8300_GPIO_B2,
+		.tx   = H8300_GPIO_B0,
+	},
+	{    /* SCI1 */
+		.port = H8300_GPIO_P3,
+		.rx   = H8300_GPIO_B3,
+		.tx   = H8300_GPIO_B1,
+	},
+	{    /* SCI2 */
+		.port = H8300_GPIO_P5,
+		.rx   = H8300_GPIO_B1,
+		.tx   = H8300_GPIO_B0,
+	}
+#endif
+};
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7708)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+	if (port->mapbase == 0xfffffe80)
+		return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */
+	return 1;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+	if (port->mapbase == 0xfffffe80)
+		return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCI */
+	if (port->mapbase == 0xa4000150)
+		return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xa4000140)
+		return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
+	return 1;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+#ifndef SCIF_ONLY
+	if (port->mapbase == 0xffe00000)
+		return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
+#endif
+#ifndef SCI_ONLY
+	if (port->mapbase == 0xffe80000)
+		return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
+#endif
+	return 1;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+	if (port->mapbase == 0xfe600000)
+		return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xfe610000)
+		return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+	if (port->mapbase == 0xfe620000)
+		return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+}
+#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+	if (port->mapbase == 0xffe00000)
+		return ctrl_inw(SCSPTR1)&0x0001 ? 1 : 0; /* SCIF */
+	else
+		return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
+
+}
+#elif defined(__H8300H__) || defined(__H8300S__)
+static inline int sci_rxd_in(struct sci_port *port)
+{
+	int ch = (port->base - SMR0) >> 3;
+	return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
+}
+#endif
+
+/*
+ * Values for the BitRate Register (SCBRR)
+ *
+ * The values are actually divisors for a frequency which can
+ * be internal to the SH3 (14.7456MHz) or derived from an external
+ * clock source.  This driver assumes the internal clock is used;
+ * to support using an external clock source, config options or
+ * possibly command-line options would need to be added.
+ *
+ * Also, to support speeds below 2400 (why?) the lower 2 bits of
+ * the SCSMR register would also need to be set to non-zero values.
+ *
+ * -- Greg Banks 27Feb2000
+ *
+ * Answer: The SCBRR register is only eight bits, and the value in
+ * it gets larger with lower baud rates. At around 2400 (depending on
+ * the peripherial module clock) you run out of bits. However the
+ * lower two bits of SCSMR allow the module clock to be divided down,
+ * scaling the value which is needed in SCBRR.
+ *
+ * -- Stuart Menefy - 23 May 2000
+ *
+ * I meant, why would anyone bother with bitrates below 2400.
+ *
+ * -- Greg Banks - 7Jul2000
+ *
+ * You "speedist"!  How will I use my 110bps ASR-33 teletype with paper
+ * tape reader as a console!
+ *
+ * -- Mitch Davis - 15 Jul 2000
+ */
+
+#define PCLK           (current_cpu_data.module_clock)
+
+#if !defined(__H8300H__) && !defined(__H8300S__)
+#define SCBRR_VALUE(bps) ((PCLK+16*bps)/(32*bps)-1)
+#else
+#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
+#endif
+#define BPS_2400       SCBRR_VALUE(2400)
+#define BPS_4800       SCBRR_VALUE(4800)
+#define BPS_9600       SCBRR_VALUE(9600)
+#define BPS_19200      SCBRR_VALUE(19200)
+#define BPS_38400      SCBRR_VALUE(38400)
+#define BPS_57600      SCBRR_VALUE(57600)
+#define BPS_115200     SCBRR_VALUE(115200)
+
diff -Nru a/drivers/usb/Kconfig b/drivers/usb/Kconfig
--- a/drivers/usb/Kconfig	Sat Apr  3 19:38:41 2004
+++ b/drivers/usb/Kconfig	Sat Apr  3 19:38:41 2004
@@ -6,32 +6,36 @@
 
 # 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.
+	  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 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>.
+	  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 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.
+	  If your system has a device-side USB port, used in the peripheral
+	  side of the USB protocol, see the "USB Gadget" framework instead.
 
-	  It doesn't normally hurt to select them all if you are not certain.
+	  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 -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/Makefile	Sat Apr  3 19:38:55 2004
@@ -20,10 +20,15 @@
 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_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 -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c
--- a/drivers/usb/class/audio.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/class/audio.c	Sat Apr  3 19:38:56 2004
@@ -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 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 @@
 	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 @@
 	}
 
 	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 @@
 		    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_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 @@
 	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 @@
 
 	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 @@
 		    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 @@
 	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 @@
 	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 @@
 {
 	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 @@
 	/* 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 @@
 	/* 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 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 @@
 		       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 @@
 			   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 @@
 	 * 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 -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
--- a/drivers/usb/class/bluetty.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/usb/class/bluetty.c	Sat Apr  3 19:38:54 2004
@@ -1025,7 +1025,7 @@
 	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 -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
--- a/drivers/usb/class/cdc-acm.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/usb/class/cdc-acm.c	Sat Apr  3 19:38:45 2004
@@ -595,12 +595,12 @@
 			 * 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 -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
--- a/drivers/usb/class/usb-midi.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/usb/class/usb-midi.c	Sat Apr  3 19:38:41 2004
@@ -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 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 @@
 				epout = i;
 			}
 			if ( epin >= 0 && epout >= 0 ) {
-				return alt;
+				return interface->desc.bAlternateSetting;
 			}
 		}
 	}
@@ -1780,12 +1779,13 @@
  *  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 @@
 		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 @@
 	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 @@
  *  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 @@
 	   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 @@
 {
 	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 @@
 
 	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 -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
--- a/drivers/usb/class/usblp.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/usb/class/usblp.c	Sat Apr  3 19:38:41 2004
@@ -133,6 +133,7 @@
 	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 @@
 	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 @@
 
 		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 @@
 	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 @@
 	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 @@
 			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 -Nru a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
--- a/drivers/usb/core/buffer.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/core/buffer.c	Sat Apr  3 19:38:56 2004
@@ -51,8 +51,8 @@
  * @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 @@
 	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 @@
 
 	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 -Nru a/drivers/usb/core/config.c b/drivers/usb/core/config.c
--- a/drivers/usb/core/config.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/usb/core/config.c	Sat Apr  3 19:38:40 2004
@@ -72,13 +72,10 @@
 	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 @@
 			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 @@
 			struct usb_interface *ifp = cf->interface[i];
 
 			if (ifp)
-				put_device(&ifp->dev);
+				usb_free_intf(ifp);
 		}
 	}
 	kfree(dev->config);
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/core/devio.c	Sat Apr  3 19:38:43 2004
@@ -430,19 +430,14 @@
 
 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 @@
 		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 @@
 		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 -Nru a/drivers/usb/core/driverfs.c b/drivers/usb/core/driverfs.c
--- a/drivers/usb/core/driverfs.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/usb/core/driverfs.c	Sat Apr  3 19:38:42 2004
@@ -166,13 +166,9 @@
 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 -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/core/hcd-pci.c	Sat Apr  3 19:38:43 2004
@@ -147,8 +147,12 @@
 	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 -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/usb/core/hcd.c	Sat Apr  3 19:38:44 2004
@@ -1213,7 +1213,7 @@
 			break;
 	}
 	if (tmp != &urb->urb_list) {
-		retval = -EINVAL;
+		retval = -EIDRM;
 		goto done;
 	}
 
@@ -1294,7 +1294,7 @@
 	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 -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/core/hub.c	Sat Apr  3 19:38:43 2004
@@ -560,7 +560,7 @@
 	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 @@
 
 	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 -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/usb/core/message.c	Sat Apr  3 19:38:42 2004
@@ -783,16 +783,19 @@
  */
 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)
+{
+}
+
 /*
  * usb_disable_device - Disable all the endpoints for a USB device
  * @dev: the device whose endpoints are being disabled
@@ -827,7 +830,7 @@
 			interface = dev->actconfig->interface[i];
 			dev_dbg (&dev->dev, "unregistering interface %s\n",
 				interface->dev.bus_id);
-			device_del(&interface->dev);
+			device_unregister (&interface->dev);
 		}
 		dev->actconfig = 0;
 		if (dev->state == USB_STATE_CONFIGURED)
@@ -876,12 +879,11 @@
 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 +922,7 @@
 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 +932,15 @@
 		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 +961,7 @@
 	/* 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 +969,11 @@
 	 * 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 +1047,19 @@
 	/* 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 +1148,34 @@
 		 */
 		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 -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/usb/core/urb.c	Sat Apr  3 19:38:44 2004
@@ -116,7 +116,8 @@
  * 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 @@
  *
  * 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 @@
  *
  * 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 @@
  * 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 @@
  * 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 -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/core/usb.c	Sat Apr  3 19:38:43 2004
@@ -189,7 +189,7 @@
 }
 
 /**
- * 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 @@
 }
 
 /**
+ * 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 @@
 
 		/* 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 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 					DMA_TO_DEVICE);
 	}
 }
+#endif
 
 /**
  * usb_buffer_unmap - free DMA mapping(s) for an urb
@@ -1403,6 +1438,13 @@
 			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 @@
 	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_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_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 -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
--- a/drivers/usb/gadget/Kconfig	Sat Apr  3 19:38:42 2004
+++ b/drivers/usb/gadget/Kconfig	Sat Apr  3 19:38:42 2004
@@ -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 @@
 	   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 @@
 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 @@
 
 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 -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
--- a/drivers/usb/gadget/Makefile	Sat Apr  3 19:38:41 2004
+++ b/drivers/usb/gadget/Makefile	Sat Apr  3 19:38:41 2004
@@ -8,8 +8,8 @@
 #
 # 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 -Nru a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/config.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
--- a/drivers/usb/gadget/ether.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/gadget/ether.c	Sat Apr  3 19:38:56 2004
@@ -124,7 +124,6 @@
  * 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 @@
 #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 @@
 #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 @@
 /* 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 @@
 	.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 @@
 	.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 @@
 /* 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 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 @@
 
 		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 @@
 			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 @@
 #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 @@
 #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 @@
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver eth_driver = {
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 	.speed		= USB_SPEED_HIGH,
 #else
 	.speed		= USB_SPEED_FULL,
diff -Nru a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/gadget_chips.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
--- a/drivers/usb/gadget/net2280.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/usb/gadget/net2280.c	Sat Apr  3 19:38:41 2004
@@ -2663,7 +2663,7 @@
 
 /* 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 @@
 	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 @@
 	.id_table =	pci_ids,
 
 	.probe =	net2280_probe,
-	.remove =	__exit_p(net2280_remove),
+	.remove =	net2280_remove,
 
 	/* FIXME add power management support */
 };
diff -Nru a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
--- a/drivers/usb/gadget/usbstring.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/usb/gadget/usbstring.c	Sat Apr  3 19:38:45 2004
@@ -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 @@
 
 	/* 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 -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
--- a/drivers/usb/gadget/zero.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/gadget/zero.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 /*-------------------------------------------------------------------------*/
 
 /*
+ * 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 @@
  * 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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #	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 @@
 /*
  * 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 @@
 
 /* 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 @@
 	.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 @@
 	.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 @@
 	.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 @@
  * 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 @@
 	.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 @@
 /* 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 @@
  * 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 @@
 			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 @@
 	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 @@
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver zero_driver = {
-#ifdef HIGHSPEED
+#ifdef CONFIG_USB_GADGET_DUALSPEED
 	.speed		= USB_SPEED_HIGH,
 #else
 	.speed		= USB_SPEED_FULL,
diff -Nru a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
--- a/drivers/usb/host/Kconfig	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/host/Kconfig	Sat Apr  3 19:38:56 2004
@@ -29,6 +29,15 @@
 	  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 -Nru a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
--- a/drivers/usb/host/ehci-dbg.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/host/ehci-dbg.c	Sat Apr  3 19:38:55 2004
@@ -579,7 +579,11 @@
 				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 -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/usb/host/ehci-hcd.c	Sat Apr  3 19:38:45 2004
@@ -106,8 +106,6 @@
 #undef EHCI_VERBOSE_DEBUG
 #undef EHCI_URB_TRACE
 
-// #define have_split_iso
-
 #ifdef DEBUG
 #define EHCI_STATS
 #endif
@@ -676,6 +674,7 @@
 
 	/* 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 @@
 	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 -Nru a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
--- a/drivers/usb/host/ehci-sched.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/usb/host/ehci-sched.c	Sat Apr  3 19:38:42 2004
@@ -53,14 +53,10 @@
 		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 @@
 			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 @@
 			hw_p = &q->sitd->hw_next;
 			q = &q->sitd->sitd_next;
 			break;
-#endif /* have_split_iso */
 		default:
 			BUG ();
 		}
@@ -229,7 +223,8 @@
 				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 @@
 				}
 				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 @@
 		// 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 @@
 	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 @@
 		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 @@
 			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->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 @@
 	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 @@
 
 		/* we know urb->interval is 2^N uframes */
 		uframe += period;
-		uframe %= mod;
-	} while (uframe != end);
+	} while (uframe < mod);
 	return 1;
 }
 
@@ -933,7 +951,6 @@
 	u32			mod,
 	struct ehci_iso_stream	*stream,
 	u32			uframe,
-	u32			end,
 	struct ehci_iso_sched	*sched,
 	u32			period_uframes
 )
@@ -952,12 +969,20 @@
 	 */
 
 	/* 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 @@
 		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 @@
 	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 @@
 
 	/* 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 @@
 		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 @@
 	 */
 	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 @@
 	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 @@
 	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 @@
 				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 @@
 				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 -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/host/ehci.h	Sat Apr  3 19:38:55 2004
@@ -492,16 +492,16 @@
 /*
  * 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 @@
 
 #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 */
@@ -551,8 +551,6 @@
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
-
-#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
 
 #ifndef DEBUG
 #define STUB_DEBUG_FILES
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/host/uhci-hcd.c	Sat Apr  3 19:38:55 2004
@@ -781,7 +781,8 @@
 /*
  * 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 @@
 		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 @@
 		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 @@
 
 	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 @@
 		}
 	}
 
-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 @@
 		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 @@
 }
 
 /*
- * 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 @@
 		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 @@
 		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 @@
 	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 @@
 {
 	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 @@
 	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_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 @@
 	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 @@
 
 	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 -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h	Sat Apr  3 19:38:54 2004
+++ b/drivers/usb/host/uhci-hcd.h	Sat Apr  3 19:38:54 2004
@@ -141,7 +141,7 @@
 				 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 @@
 	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 -Nru a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c
--- a/drivers/usb/image/hpusbscsi.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/image/hpusbscsi.c	Sat Apr  3 19:38:56 2004
@@ -42,7 +42,7 @@
 		    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 -Nru a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
--- a/drivers/usb/image/mdc800.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/image/mdc800.c	Sat Apr  3 19:38:43 2004
@@ -431,7 +431,7 @@
 		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 @@
 	}
 
 
-	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);
@@ -550,8 +543,6 @@
 		usb_unlink_urb (mdc800->irq_urb);
 		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 -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
--- a/drivers/usb/image/microtek.c	Sat Apr  3 19:38:57 2004
+++ b/drivers/usb/image/microtek.c	Sat Apr  3 19:38:57 2004
@@ -693,7 +693,6 @@
 			 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 @@
 	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 @@
 		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 */
@@ -765,20 +764,6 @@
 	if ( ep_out == -1 ) {
 		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;
 	}
 	
 	
diff -Nru a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
--- a/drivers/usb/input/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/drivers/usb/input/Kconfig	Sat Apr  3 19:38:54 2004
@@ -179,6 +179,18 @@
 	  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 @@
 
 	  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 -Nru a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
--- a/drivers/usb/input/Makefile	Sat Apr  3 19:38:44 2004
+++ b/drivers/usb/input/Makefile	Sat Apr  3 19:38:44 2004
@@ -27,10 +27,12 @@
 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 -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
--- a/drivers/usb/input/aiptek.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/usb/input/aiptek.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 	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 @@
 		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 @@
 		(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 @@
 	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 @@
 
 	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 -Nru a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/ati_remote.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/usb/input/hid-core.c	Sat Apr  3 19:38:44 2004
@@ -224,6 +224,9 @@
 	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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 #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 @@
 #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 @@
 	{ 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 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 @@
 			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 -Nru a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
--- a/drivers/usb/input/hid-ff.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/input/hid-ff.c	Sat Apr  3 19:38:43 2004
@@ -29,7 +29,7 @@
 
 #include <linux/input.h>
 
-#define DEBUG
+#undef DEBUG
 #include <linux/usb.h>
 
 #include "hid.h"
diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/input/hid-input.c	Sat Apr  3 19:38:43 2004
@@ -377,7 +377,8 @@
 
 	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 @@
 
 	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 @@
 		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 @@
 		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 -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
--- a/drivers/usb/input/hid.h	Sat Apr  3 19:38:40 2004
+++ b/drivers/usb/input/hid.h	Sat Apr  3 19:38:40 2004
@@ -201,15 +201,16 @@
  * 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 @@
 
 #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 -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/input/hiddev.c	Sat Apr  3 19:38:43 2004
@@ -403,7 +403,8 @@
 	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 @@
 		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 -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c
--- a/drivers/usb/input/kbtab.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/usb/input/kbtab.c	Sat Apr  3 19:38:40 2004
@@ -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 @@
 		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 @@
 
 	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 @@
 		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 @@
 		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 -Nru a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/input/mtouchusb.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
--- a/drivers/usb/input/pid.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/input/pid.c	Sat Apr  3 19:38:55 2004
@@ -200,6 +200,7 @@
 			    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 -Nru a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
--- a/drivers/usb/input/usbkbd.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/input/usbkbd.c	Sat Apr  3 19:38:56 2004
@@ -240,7 +240,7 @@
 	char path[64];
 	char *buf;
 
-	interface = &iface->altsetting[iface->act_altsetting];
+	interface = iface->cur_altsetting;
 
 	if (interface->desc.bNumEndpoints != 1)
 		return -ENODEV;
diff -Nru a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
--- a/drivers/usb/input/usbmouse.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/input/usbmouse.c	Sat Apr  3 19:38:55 2004
@@ -131,7 +131,7 @@
 	char path[64];
 	char *buf;
 
-	interface = &intf->altsetting[intf->act_altsetting];
+	interface = intf->cur_altsetting;
 
 	if (interface->desc.bNumEndpoints != 1) 
 		return -ENODEV;
diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
--- a/drivers/usb/input/wacom.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/usb/input/wacom.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 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 @@
 	}
 
 	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 @@
 			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 @@
 
 	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 @@
 		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 @@
 			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 @@
 		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 @@
 	}
 
 	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 @@
 
 	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 @@
 			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 @@
 
 	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 @@
 		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 @@
 
 				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 @@
 		}
 	}
 	
+	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 @@
 	{ "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 @@
 	{ 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 @@
 	{ 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 @@
 		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 @@
 		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 @@
 			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 -Nru a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig
--- a/drivers/usb/media/Kconfig	Sat Apr  3 19:38:40 2004
+++ b/drivers/usb/media/Kconfig	Sat Apr  3 19:38:40 2004
@@ -202,4 +202,4 @@
 	  This code is also available as a module ( = code which can be
 	  inserted in and removed from the running kernel whenever you want).
 	  The module will be called w9968cf.o. If you want to compile it as a
-	  module, say M here and read <file:Documentation/modules.txt>.
+	  module, say M here and read <file:Documentation/kbuild/modules.txt>.
diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
--- a/drivers/usb/media/se401.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/usb/media/se401.c	Sat Apr  3 19:38:42 2004
@@ -369,7 +369,7 @@
 				se401->scratch_overflow=0;
 				se401->scratch_next++;
 				if (se401->scratch_next>=SE401_NUMSCRATCH)
-					se401->scratch_next=0;;
+					se401->scratch_next=0;
 				break;
 			}
 		}
diff -Nru a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
--- a/drivers/usb/media/stv680.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/usb/media/stv680.c	Sat Apr  3 19:38:45 2004
@@ -641,7 +641,7 @@
 			stv680->scratch_overflow = 0;
 			stv680->scratch_next++;
 			if (stv680->scratch_next >= STV680_NUMSCRATCH)
-				stv680->scratch_next = 0;;
+				stv680->scratch_next = 0;
 			break;
 		}		/* switch  */
 	} else {
diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
--- a/drivers/usb/misc/Kconfig	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/misc/Kconfig	Sat Apr  3 19:38:56 2004
@@ -86,17 +86,6 @@
 	  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 -Nru a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
--- a/drivers/usb/misc/Makefile	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/misc/Makefile	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c
--- a/drivers/usb/misc/brlvger.c	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
--- a/drivers/usb/misc/usbtest.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/misc/usbtest.c	Sat Apr  3 19:38:56 2004
@@ -149,8 +149,6 @@
 				if (!out)
 					out = e;
 			}
-			if (in && out)
-				goto found;
 			continue;
 try_iso:
 			if (e->desc.bEndpointAddress & USB_DIR_IN) {
@@ -160,9 +158,9 @@
 				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 @@
 			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 struct urb *simple_alloc_urb (
 	struct usb_device	*udev,
 	int			pipe,
-	long			bytes
+	unsigned long		bytes
 )
 {
 	struct urb		*urb;
@@ -490,7 +489,7 @@
 	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 @@
 {
 	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 @@
 			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 @@
 			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 @@
 			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 @@
 	 * 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 @@
 		 * "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 @@
 			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 @@
 			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 @@
 	.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 -Nru a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
--- a/drivers/usb/net/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/drivers/usb/net/Kconfig	Sat Apr  3 19:38:54 2004
@@ -131,6 +131,14 @@
 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 -Nru a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
--- a/drivers/usb/net/pegasus.h	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/net/pegasus.h	Sat Apr  3 19:38:56 2004
@@ -128,6 +128,7 @@
 #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 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 @@
 		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,
@@ -262,6 +268,8 @@
 PEGASUS_DEV( "NETGEAR FA101", VENDOR_NETGEAR, 0x1020,
 		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 )
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/net/usbnet.c	Sat Apr  3 19:38:43 2004
@@ -384,6 +384,23 @@
 }
 
 
+#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 @@
 		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 @@
 
 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
@@ -3310,6 +3334,15 @@
 		 | USB_DEVICE_ID_MATCH_DEVICE,
 	.idVendor               = 0x04DD,
 	.idProduct              = 0x9032,	/* SL-6000 */
+	.bInterfaceClass        = 0x02,
+	.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,
diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
--- a/drivers/usb/serial/empeg.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/serial/empeg.c	Sat Apr  3 19:38:56 2004
@@ -155,7 +155,7 @@
 static int empeg_open (struct usb_serial_port *port, struct file *filp)
 {
 	struct usb_serial *serial = port->serial;
-	int result = 0;;
+	int result = 0;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/serial/ftdi_sio.c	Sat Apr  3 19:38:55 2004
@@ -286,6 +286,7 @@
 
 
 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_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_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 -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
--- a/drivers/usb/serial/ftdi_sio.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/serial/ftdi_sio.h	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
--- a/drivers/usb/serial/kl5kusb105.c	Sat Apr  3 19:38:44 2004
+++ b/drivers/usb/serial/kl5kusb105.c	Sat Apr  3 19:38:44 2004
@@ -273,6 +273,7 @@
 
 	/* 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 @@
 		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 -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
--- a/drivers/usb/serial/mct_u232.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/usb/serial/mct_u232.c	Sat Apr  3 19:38:45 2004
@@ -511,7 +511,7 @@
 
 	/* only do something if we have a bulk out endpoint */
 	if (!serial->num_bulk_out)
-		return(0);;
+		return(0);
 	
 	/* another write is still pending? */
 	if (port->write_urb->status == -EINPROGRESS) {
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/serial/pl2303.c	Sat Apr  3 19:38:43 2004
@@ -403,7 +403,7 @@
 {
 	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 @@
 	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);			\
@@ -432,6 +436,8 @@
 	SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1);
 	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) {
diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
--- a/drivers/usb/serial/usb-serial.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/serial/usb-serial.c	Sat Apr  3 19:38:43 2004
@@ -391,7 +391,7 @@
 	struct usb_serial *serial = serial_table[index];
 
 	if (serial)
-		kobject_get (&serial->kobj);
+		kref_get(&serial->kref);
 	return serial;
 }
 
@@ -486,7 +486,7 @@
 		if (retval) {
 			port->open_count = 0;
 			module_put(serial->type->owner);
-			kobject_put(&serial->kobj);
+			kref_put(&serial->kref);
 		}
 	}
 bailout:
@@ -518,7 +518,7 @@
 	}
 
 	module_put(port->serial->type->owner);
-	kobject_put(&port->serial->kobj);
+	kref_put(&port->serial->kref);
 }
 
 static int serial_write (struct tty_struct * tty, int from_user, const unsigned char *buf, int count)
@@ -748,7 +748,7 @@
 			begin += length;
 			length = 0;
 		}
-		kobject_put(&serial->kobj);
+		kref_put(&serial->kref);
 	}
 	*eof = 1;
 done:
@@ -830,15 +830,15 @@
 	wake_up_interruptible(&tty->write_wait);
 }
 
-static void destroy_serial (struct kobject *kobj)
+static void destroy_serial(struct kref *kref)
 {
 	struct usb_serial *serial;
 	struct usb_serial_port *port;
 	int i;
 
-	dbg ("%s - %s", __FUNCTION__, kobj->name);
+	serial = to_usb_serial(kref);
 
-	serial = to_usb_serial(kobj);
+	dbg ("%s - %s", __FUNCTION__, serial->type->name);
 	serial_shutdown (serial);
 
 	/* return the minor range that this device had */
@@ -886,10 +886,6 @@
 	kfree (serial);
 }
 
-static struct kobj_type usb_serial_kobj_type = {
-	.release = destroy_serial,
-};
-
 static void port_release(struct device *dev)
 {
 	struct usb_serial_port *port = to_usb_serial_port(dev);
@@ -930,10 +926,7 @@
 	serial->interface = interface;
 	serial->vendor = dev->descriptor.idVendor;
 	serial->product = dev->descriptor.idProduct;
-
-	/* initialize the kobject portion of the usb_device */
-	kobject_init(&serial->kobj);
-	serial->kobj.ktype = &usb_serial_kobj_type;
+	kref_init(&serial->kref, destroy_serial);
 
 	return serial;
 }
@@ -1006,7 +999,7 @@
 
 	/* 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;
 		
@@ -1284,7 +1277,7 @@
 	if (serial) {
 		/* let the last holder of this object 
 		 * cause it to be cleaned up */
-		kobject_put (&serial->kobj);
+		kref_put(&serial->kref);
 	}
 	dev_info(dev, "device disconnected\n");
 }
diff -Nru a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
--- a/drivers/usb/serial/usb-serial.h	Sat Apr  3 19:38:57 2004
+++ b/drivers/usb/serial/usb-serial.h	Sat Apr  3 19:38:57 2004
@@ -55,6 +55,7 @@
 #define __LINUX_USB_SERIAL_H
 
 #include <linux/config.h>
+#include <linux/kref.h>
 
 #define SERIAL_TTY_MAJOR	188	/* Nice legal number now */
 #define SERIAL_TTY_MINORS	255	/* loads of devices :) */
@@ -163,10 +164,10 @@
 	__u16				vendor;
 	__u16				product;
 	struct usb_serial_port *	port[MAX_NUM_PORTS];
-	struct kobject			kobj;
+	struct kref			kref;
 	void *				private;
 };
-#define to_usb_serial(d) container_of(d, struct usb_serial, kobj)
+#define to_usb_serial(d) container_of(d, struct usb_serial, kref)
 
 #define NUM_DONT_CARE	(-1)
 
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/usb/serial/visor.c	Sat Apr  3 19:38:42 2004
@@ -239,6 +239,8 @@
 		.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 @@
 	{ 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 -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h	Sat Apr  3 19:38:55 2004
+++ b/drivers/usb/serial/visor.h	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
--- a/drivers/usb/storage/Kconfig	Sat Apr  3 19:38:56 2004
+++ b/drivers/usb/storage/Kconfig	Sat Apr  3 19:38:56 2004
@@ -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 -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
--- a/drivers/usb/storage/scsiglue.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/usb/storage/scsiglue.c	Sat Apr  3 19:38:43 2004
@@ -64,8 +64,10 @@
 	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
@@ -75,6 +77,16 @@
 	 * have the desired effect because, except at the beginning and
 	 * 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. */
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/usb/storage/transport.c	Sat Apr  3 19:38:42 2004
@@ -563,9 +563,9 @@
 
 	/*
 	 * 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 @@
 		 * 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 @@
 	}
 
 	/* 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 -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h	Sat Apr  3 19:38:54 2004
+++ b/drivers/usb/storage/unusual_devs.h	Sat Apr  3 19:38:54 2004
@@ -261,6 +261,14 @@
 		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(  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 @@
 		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 @@
 		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 @@
  *   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 @@
 		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 @@
                 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 -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
--- a/drivers/usb/storage/usb.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/usb/storage/usb.c	Sat Apr  3 19:38:42 2004
@@ -423,7 +423,7 @@
 	/* 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 @@
 {
 	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_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 @@
 	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);
@@ -953,8 +954,6 @@
 
 	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 -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
--- a/drivers/usb/storage/usb.h	Sat Apr  3 19:38:45 2004
+++ b/drivers/usb/storage/usb.h	Sat Apr  3 19:38:45 2004
@@ -176,6 +176,5 @@
  * 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 -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig
--- a/drivers/video/Kconfig	Sat Apr  3 19:38:40 2004
+++ b/drivers/video/Kconfig	Sat Apr  3 19:38:40 2004
@@ -76,10 +76,6 @@
 	  hardware found in Acorn RISC PCs and other ARM-based machines.  If
 	  unsure, say N.
 
-config FB_ANAKIN
-	bool "Anakin LCD support"
-	depends on FB && ARM && ARCH_ANAKIN
-
 config FB_CLPS711X
 	bool "CLPS711X LCD support"
 	depends on FB && ARM && ARCH_CLPS711X
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile	Sat Apr  3 19:38:41 2004
+++ b/drivers/video/Makefile	Sat Apr  3 19:38:41 2004
@@ -28,7 +28,6 @@
 obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CT65550)          += chipsfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_ANAKIN)           += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CYBER)            += cyberfb.o
 obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
diff -Nru a/drivers/video/acornfb.c b/drivers/video/acornfb.c
--- a/drivers/video/acornfb.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/video/acornfb.c	Sat Apr  3 19:38:56 2004
@@ -29,6 +29,8 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/fb.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -1254,6 +1256,11 @@
 	printk("acornfb: freed %dK memory\n", mb_freed);
 }
 
+static struct device acornfb_device = {
+	.bus_id			= "acornfb",
+	.coherent_dma_mask	= 0xffffffff,
+};
+
 int __init
 acornfb_init(void)
 {
@@ -1263,6 +1270,8 @@
 
 	acornfb_init_fbinfo();
 
+	current_par.dev = &acornfb_device;
+
 	if (current_par.montype == -1)
 		current_par.montype = acornfb_detect_monitortype();
 
@@ -1323,37 +1332,30 @@
 
 #if defined(HAS_VIDC20)
 	if (!current_par.using_vram) {
+		dma_addr_t handle;
+		void *base;
+
 		/*
 		 * RiscPC needs to allocate the DRAM memory
 		 * for the framebuffer if we are not using
-		 * VRAM.  Archimedes/A5000 machines use a
-		 * fixed address for their framebuffers.
+		 * VRAM.
 		 */
-		unsigned long page, top, base;
-		int order = get_order(size);
-
-		base = __get_free_pages(GFP_KERNEL, order);
-		if (base == 0) {
+		base = dma_alloc_writecombine(current_par.dev, size, &handle,
+					      GFP_KERNEL);
+		if (base == NULL) {
 			printk(KERN_ERR "acornfb: unable to allocate screen "
 			       "memory\n");
 			return -ENOMEM;
 		}
-		top = base + (PAGE_SIZE << order);
-
-		/* Mark the framebuffer pages as reserved so mmap will work. */
-		for (page = base; page < PAGE_ALIGN(base + size); page += PAGE_SIZE)
-			SetPageReserved(virt_to_page(page));
-		/* Hand back any excess pages that we allocated. */
-		for (page = base + size; page < top; page += PAGE_SIZE)
-			free_page(page);
 
-		fb_info.screen_base = (char *)base;
-		fb_info.fix.smem_start = virt_to_phys(fb_info.screen_base);
+		fb_info.screen_base = base;
+		fb_info.fix.smem_start = handle;
 	}
 #endif
 #if defined(HAS_VIDC)
 	/*
-	 * Free unused pages
+	 * Archimedes/A5000 machines use a fixed address for their
+	 * framebuffers.  Free unused pages
 	 */
 	free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
 #endif
diff -Nru a/drivers/video/acornfb.h b/drivers/video/acornfb.h
--- a/drivers/video/acornfb.h	Sat Apr  3 19:38:44 2004
+++ b/drivers/video/acornfb.h	Sat Apr  3 19:38:45 2004
@@ -47,6 +47,7 @@
 };
 
 struct acornfb_par {
+	struct device	*dev;
 	unsigned long	screen_end;
 	unsigned int	dram_size;
 	unsigned int	vram_half_sam;
diff -Nru a/drivers/video/anakinfb.c b/drivers/video/anakinfb.c
--- a/drivers/video/anakinfb.c	Sat Apr  3 19:38:44 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,102 +0,0 @@
-/*
- *  linux/drivers/video/anakinfb.c
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   23-Apr-2001 TTC	Created
- */
-
-#include <linux/types.h>
-#include <linux/fb.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/io.h>
-
-static u32 colreg[17];
-static struct fb_info fb_info;
-
-static struct fb_var_screeninfo anakinfb_var = {
-	.xres 		= 400,
-	.yres 		= 234,
-	.xres_virtual 	= 400,
-	.yres_virtual 	= 234,
-	.bits_per_pixel = 16,
-	.red 		= { 11, 5, 0 },
-	.green 		= {  5, 6, 0 }, 
-	.blue 		= {  0, 5, 0 },
-	.activate	= FB_ACTIVATE_NOW,
-	.height		= -1,
-	.width		= -1,
-	.vmode		= FB_VMODE_NONINTERLACED,
-};
-
-static struct fb_fix_screeninfo anakinfb_fix = {
-	.id 		= "AnakinFB",
-	.smem_start 	= VGA_START,
-	.smem_len 	= VGA_SIZE,
-	.type 		= FB_TYPE_PACKED_PIXELS,
-	.visual 	= FB_VISUAL_TRUECOLOR,
-	.line_length 	= 400*2,
-	.accel 		= FB_ACCEL_NONE,
-};
-
-static int
-anakinfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			u_int transp, struct fb_info *info)
-{
-	if (regno > 15)
-		return 1;
-
-	((u16 *)(info->pseudo_palette))[regno] = (red & 0xf800) | (green & 0xfc00 >> 5) | (blue & 0xf800 >> 11);
-	return 0;
-}
-
-static struct fb_ops anakinfb_ops = {
-	.owner		= THIS_MODULE,
-	.fb_setcolreg	= anakinfb_setcolreg,
-	.fb_fillrect	= cfb_fillrect,
-	.fb_copyarea	= cfb_copyarea,
-	.fb_imageblit	= cfb_imageblit,
-	.fb_cursor	= soft_cursor,
-};
-
-int __init
-anakinfb_init(void)
-{
-	memset(&fb_info, 0, sizeof(struct fb_info));
-
-	fb_info.flags = FBINFO_FLAG_DEFAULT;
-	fb_info.fbops = &anakinfb_ops;
-	fb_info.var = anakinfb_var;
-	fb_info.fix = anakinfb_fix;
-	fb_info.psuedo_palette = colreg;
-	if (!(request_mem_region(VGA_START, VGA_SIZE, "vga")))
-		return -ENOMEM;
-	if (fb_info.screen_base = ioremap(VGA_START, VGA_SIZE)) {
-		release_mem_region(VGA_START, VGA_SIZE);
-		return -EIO;
-	}
-
-	fb_alloc_cmap(&fb_info.cmap, 16, 0);
-
-	if (register_framebuffer(&fb_info) < 0) {
-		iounmap(fb_info.screen_base);
-		release_mem_region(VGA_START, VGA_SIZE);
-		return -EINVAL;
-	}
-
-	MOD_INC_USE_COUNT;
-	return 0;
-}
-
-MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>");
-MODULE_DESCRIPTION("Anakin framebuffer driver");
-MODULE_SUPPORTED_DEVICE("fb");
diff -Nru a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
--- a/drivers/video/aty/radeon_monitor.c	Sat Apr  3 19:38:40 2004
+++ b/drivers/video/aty/radeon_monitor.c	Sat Apr  3 19:38:40 2004
@@ -640,21 +640,21 @@
 #ifdef CONFIG_PPC_OF
 	/* iBook2's */
 	if (machine_is_compatible("PowerBook4,3")) {
-		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;;
+		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;
 		rinfo->panel_info.post_divider = 0x6;
 		rinfo->panel_info.fbk_divider = 0xad;
 		rinfo->panel_info.use_bios_dividers = 1;
 	}
 	/* Aluminium PowerBook 17" */
 	if (machine_is_compatible("PowerBook5,3")) {
-		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;;
+		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;
 		rinfo->panel_info.post_divider = 0x4;
 		rinfo->panel_info.fbk_divider = 0x80;
 		rinfo->panel_info.use_bios_dividers = 1;
 	}
 	/* iBook G4 */
 	if (machine_is_compatible("PowerBook6,3")) {
-		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;;
+		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;
 		rinfo->panel_info.post_divider = 0x6;
 		rinfo->panel_info.fbk_divider = 0xad;
 		rinfo->panel_info.use_bios_dividers = 1;
@@ -757,7 +757,7 @@
 	    && 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 -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
--- a/drivers/video/console/fbcon.c	Sat Apr  3 19:38:45 2004
+++ b/drivers/video/console/fbcon.c	Sat Apr  3 19:38:45 2004
@@ -309,94 +309,6 @@
 }
 
 /*
- * 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 @@
 	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 @@
 	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 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 */
@@ -746,19 +662,17 @@
 		struct display *q = &fb_display[i];
 		struct vc_data *tmp = vc_cons[i].d;
 		
-		if (vc->vc_font.width > 32) {
-			/* If we are not the first console on this
-			   fb, copy the font from that console */
-			vc->vc_font.width = tmp->vc_font.width;
-			vc->vc_font.height = tmp->vc_font.height;
-			vc->vc_font.data = p->fontdata = q->fontdata;
-			p->userfont = q->userfont;
-			if (p->userfont) {
-				REFCOUNT(p->fontdata)++;
-				charcnt = FNTCHARCNT(p->fontdata);
-			}
-			con_copy_unimap(vc->vc_num, i);
+		/* If we are not the first console on this
+		   fb, copy the font from that console */
+		vc->vc_font.width = tmp->vc_font.width;
+		vc->vc_font.height = tmp->vc_font.height;
+		vc->vc_font.data = p->fontdata = q->fontdata;
+		p->userfont = q->userfont;
+		if (p->userfont) {
+			REFCOUNT(p->fontdata)++;
+			charcnt = FNTCHARCNT(p->fontdata);
 		}
+		con_copy_unimap(vc->vc_num, i);
 	}
 
 	if (!p->fontdata) {
@@ -958,11 +872,19 @@
 		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 +894,28 @@
 	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 +2288,7 @@
 {
 	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 +2296,11 @@
 		fbcon_event_notifier_registered = 1;
 	} 
 	release_console_sem();
-
 	return 0;
 }
 
+#ifdef MODULE
+
 void __exit fb_console_exit(void)
 {
 	acquire_console_sem();
@@ -2369,6 +2314,8 @@
 
 module_init(fb_console_init);
 module_exit(fb_console_exit);
+
+#endif
 
 /*
  *  Visible symbols for modules
diff -Nru a/drivers/video/dnfb.c b/drivers/video/dnfb.c
--- a/drivers/video/dnfb.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/video/dnfb.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 	.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 @@
 	.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 @@
 	return 0;
 }
 
-static 
+static
 void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 {
 
@@ -224,21 +222,38 @@
 	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 @@
 	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 -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	Sat Apr  3 19:38:31 2004
+++ b/drivers/video/fbmem.c	Sat Apr  3 19:38:31 2004
@@ -55,7 +55,6 @@
 extern int acornfb_setup(char*);
 extern int amifb_init(void);
 extern int amifb_setup(char*);
-extern int anakinfb_init(void);
 extern int atafb_init(void);
 extern int atafb_setup(char*);
 extern int macfb_init(void);
@@ -180,9 +179,6 @@
 #ifdef CONFIG_FB_AMIGA
 	{ "amifb", amifb_init, amifb_setup },
 #endif
-#ifdef CONFIG_FB_ANAKIN
-	{ "anakinfb", anakinfb_init, NULL },
-#endif
 #ifdef CONFIG_FB_CLPS711X
 	{ "clps711xfb", clps711xfb_init, NULL },
 #endif
@@ -1181,11 +1177,9 @@
 #elif defined(__mips__)
 	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
 	pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
-#elif defined(__sh__)
-	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
 #elif defined(__hppa__)
 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
-#elif defined(__ia64__) || defined(__arm__)
+#elif defined(__ia64__) || defined(__arm__) || defined(__sh__)
 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 #else
 #warning What do we have to do here??
diff -Nru a/drivers/video/fbmon.c b/drivers/video/fbmon.c
--- a/drivers/video/fbmon.c	Sat Apr  3 19:38:55 2004
+++ b/drivers/video/fbmon.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 	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 @@
 		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 @@
 	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 @@
 	}
 	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 @@
 	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 @@
 
 	*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 @@
 		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 @@
 
 		modes = fb_create_modedb(edid, &num_modes);
 		if (!modes) {
-			printk("None Available\n");
+			DPRINTK("None Available\n");
 			return 1;
 		}
 
@@ -767,15 +552,189 @@
 			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 @@
 
 	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) 
@@ -971,7 +899,7 @@
  */
 static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres)
 {
-	u32 duty_cycle, h_period, hblank;;
+	u32 duty_cycle, h_period, hblank;
 
 	dclk /= 1000;
 	h_period = 100 - C_VAL;
@@ -1179,7 +1107,7 @@
  * 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 @@
 		-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 -Nru a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
--- a/drivers/video/fm2fb.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/video/fm2fb.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	.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 @@
 	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 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_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 @@
      *  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);
-
-		if (fm2fb_mode == -1)
-			fm2fb_mode = FM2FB_MODE_PAL;
-
-		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;
+	is_fm = z->id == ZORRO_PROD_BSC_FRAMEMASTER_II;
+
+	if (!zorro_request_device(z,"fm2fb"))
+		return -ENXIO;
 
-		/* The below fields will go away !!!! */
-		fb_alloc_cmap(&fb_info.cmap, 16, 0);
+	info = framebuffer_alloc(256 * sizeof(u32), &z->dev);
+	if (!info) {
+		zorro_release_device(z);
+		return -ENOMEM;
+	}
 
-		if (register_framebuffer(&fb_info) < 0)
-			return -EINVAL;
+	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+		framebuffer_release(info);
+		zorro_release_device(z);
+		return -ENOMEM;
+	}
 
-		printk("fb%d: %s frame buffer device\n", fb_info.node, fb_fix.id);
-		return 0;
+	/* 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);
+
+	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 @@
 	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 -Nru a/drivers/video/hitfb.c b/drivers/video/hitfb.c
--- a/drivers/video/hitfb.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/video/hitfb.c	Sat Apr  3 19:38:41 2004
@@ -1,16 +1,16 @@
 /*
- * $Id: hitfb.c,v 1.10 2004/02/01 19:46:04 lethal Exp $
+ * $Id: hitfb.c,v 1.12 2004/03/16 00:07:51 lethal Exp $
  * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device
  * (C) 1999 Mihai Spatar
  * (C) 2000 YAEGASHI Takeshi
  * (C) 2003, 2004 Paul Mundt
- * (C) 2003 Andriy Skulysh
+ * (C) 2003, 2004 Andriy Skulysh
  *
  *  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.
  */
- 
+
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -30,139 +30,137 @@
 #include <asm/io.h>
 #include <asm/hd64461/hd64461.h>
 
+#ifdef MACH_HP600
+#include <asm/cpu/dac.h>
+#include <asm/hp6xx/hp6xx.h>
+#endif
+
+#define	WIDTH 640
+
 static struct fb_var_screeninfo hitfb_var __initdata = {
 	.activate	= FB_ACTIVATE_NOW,
 	.height		= -1,
-	.width		= -1,
-	.vmode		= FB_VMODE_NONINTERLACED,
+	.width 		= -1,
+	.vmode 		= FB_VMODE_NONINTERLACED,
 };
 
 static struct fb_fix_screeninfo hitfb_fix __initdata = {
-	.id		= "Hitachi HD64461",
-	.type		= FB_TYPE_PACKED_PIXELS,
-	.ypanstep	= 8,
-	.accel		= FB_ACCEL_NONE,
+	.id 		= "Hitachi HD64461",
+	.type 		= FB_TYPE_PACKED_PIXELS,
+	.ypanstep 	= 8,
+	.accel 		= FB_ACCEL_NONE,
 };
 
 static u32 pseudo_palette[16];
 static struct fb_info fb_info;
 
-
-#define	WIDTH 640
-
-static void hitfb_set_base(u32 offset)
+static inline void hitfb_accel_wait(void)
 {
-	fb_writew(offset>>10,HD64461_LCDCBAR);
-}
-
-static inline void hitfb_accel_wait()
-{
-	while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS)
-		;
+	while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS) ;
 }
 
 static inline void hitfb_accel_start(int truecolor)
 {
 	if (truecolor) {
-		fb_writew(6,HD64461_GRCFGR);
+		fb_writew(6, HD64461_GRCFGR);
 	} else {
-		fb_writew(7,HD64461_GRCFGR);
+		fb_writew(7, HD64461_GRCFGR);
 	}
 }
 
-static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy, 
-	u16 width, u16 height)
+static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy,
+					u16 width, u16 height)
 {
-	u32 saddr=WIDTH*dy+dx;
+	u32 saddr = WIDTH * dy + dx;
 	if (truecolor)
 		saddr <<= 1;
-	
-	fb_writew(width,HD64461_BBTDWR);
-	fb_writew(height,HD64461_BBTDHR);
-	
-	fb_writew(saddr&0xffff,HD64461_BBTDSARL);
-	fb_writew(saddr>>16,HD64461_BBTDSARH);
-}
-
-static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy, 
-	u16 width, u16 height, u16 color)
-{
-	hitfb_accel_set_dest(truecolor,dx,dy,width,height);
-
-	fb_writew(0x00f0,HD64461_BBTROPR);
-	fb_writew(16,HD64461_BBTMDR);
-	fb_writew(color,HD64461_GRSCR);
 
-	hitfb_accel_start(truecolor);
+	fb_writew(width, HD64461_BBTDWR);
+	fb_writew(height, HD64461_BBTDHR);
+
+	fb_writew(saddr & 0xffff, HD64461_BBTDSARL);
+	fb_writew(saddr >> 16, HD64461_BBTDSARH);
+
 }
 
-static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, u16 dy, 
-	u16 width, u16 height, u16 rop, u32 mask_addr)
+static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy,
+					 u16 width, u16 height, u16 color)
 {
-	u32 saddr,daddr;
-	u32 maddr=0;
-	fb_writew(rop,HD64461_BBTROPR);
-
-	if((sy<dy)||((sy==dy)&&(sx<=dx))) {
-		saddr=WIDTH*(sy+height)+sx+width;
-		daddr=WIDTH*(dy+height)+dx+width;
+	hitfb_accel_set_dest(truecolor, dx, dy, width, height);
 
-		if (mask_addr) {
-			if (truecolor) {
-				maddr=((width>>3)+1)*(height+1)-1;
-			} else {
-				maddr=(((width>>4)+1)*(height+1)-1)*2;
-			}
+	fb_writew(0x00f0, HD64461_BBTROPR);
+	fb_writew(16, HD64461_BBTMDR);
+	fb_writew(color, HD64461_GRSCR);
 
-			fb_writew((1<<5)|1,HD64461_BBTMDR);
-		} else {
-			fb_writew(1,HD64461_BBTMDR);
-		}
+	hitfb_accel_start(truecolor);
+}
+
+static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx,
+				      u16 dy, u16 width, u16 height, u16 rop,
+				      u32 mask_addr)
+{
+	u32 saddr, daddr;
+	u32 maddr = 0;
+
+	fb_writew(rop, HD64461_BBTROPR);
+	if ((sy < dy) || ((sy == dy) && (sx <= dx))) {
+		saddr = WIDTH * (sy + height) + sx + width;
+		daddr = WIDTH * (dy + height) + dx + width;
+		if (mask_addr) {
+			if (truecolor)
+				maddr = ((width >> 3) + 1) * (height + 1) - 1;
+			else
+				maddr =
+				    (((width >> 4) + 1) * (height + 1) - 1) * 2;
+
+			fb_writew((1 << 5) | 1, HD64461_BBTMDR);
+		} else
+			fb_writew(1, HD64461_BBTMDR);
 	} else {
-		saddr=WIDTH*sy+sx;
-		daddr=WIDTH*dy+dx;
+		saddr = WIDTH * sy + sx;
+		daddr = WIDTH * dy + dx;
 		if (mask_addr) {
-			fb_writew((1<<5),HD64461_BBTMDR);
+			fb_writew((1 << 5), HD64461_BBTMDR);
 		} else {
-			outw(0,HD64461_BBTMDR);
+			fb_writew(0, HD64461_BBTMDR);
 		}
 	}
-
 	if (truecolor) {
-		saddr<<=1;
-		daddr<<=1;
+		saddr <<= 1;
+		daddr <<= 1;
 	}
-
-	fb_writew(width,HD64461_BBTDWR);
-	fb_writew(height,HD64461_BBTDHR);
-	fb_writew(saddr&0xffff,HD64461_BBTSSARL);
-	fb_writew(saddr>>16,HD64461_BBTSSARH);
-	fb_writew(daddr&0xffff,HD64461_BBTDSARL);
-	fb_writew(daddr>>16,HD64461_BBTDSARH);
-
+	fb_writew(width, HD64461_BBTDWR);
+	fb_writew(height, HD64461_BBTDHR);
+	fb_writew(saddr & 0xffff, HD64461_BBTSSARL);
+	fb_writew(saddr >> 16, HD64461_BBTSSARH);
+	fb_writew(daddr & 0xffff, HD64461_BBTDSARL);
+	fb_writew(daddr >> 16, HD64461_BBTDSARH);
 	if (mask_addr) {
-		maddr+=mask_addr;
-		fb_writew(maddr&0xffff,HD64461_BBTMARL);
-		fb_writew(maddr>>16,HD64461_BBTMARH);
+		maddr += mask_addr;
+		fb_writew(maddr & 0xffff, HD64461_BBTMARL);
+		fb_writew(maddr >> 16, HD64461_BBTMARH);
 	}
 	hitfb_accel_start(truecolor);
 }
 
 static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
 {
-	if (rect->rop != ROP_COPY) {
-		cfb_fillrect(p,rect);
-	} else {
-		fb_writew(0x00f0,HD64461_BBTROPR);
-		fb_writew(16,HD64461_BBTMDR);
-
-		if (p->var.bits_per_pixel==16) {
-			fb_writew( ((u32*)(p->pseudo_palette))[rect->color] , HD64461_GRSCR );
-			hitfb_accel_set_dest(1,rect->dx,rect->dy,rect->width,rect->height);
+	if (rect->rop != ROP_COPY)
+		cfb_fillrect(p, rect);
+	else {
+		fb_writew(0x00f0, HD64461_BBTROPR);
+		fb_writew(16, HD64461_BBTMDR);
+
+		if (p->var.bits_per_pixel == 16) {
+			fb_writew(((u32 *) (p->pseudo_palette))[rect->color],
+				  HD64461_GRSCR);
+			hitfb_accel_set_dest(1, rect->dx, rect->dy, rect->width,
+					     rect->height);
 			hitfb_accel_start(1);
 		} else {
 			fb_writew(rect->color, HD64461_GRSCR);
-			hitfb_accel_set_dest(0,rect->dx,rect->dy,rect->width,rect->height);
+			hitfb_accel_set_dest(0, rect->dx, rect->dy, rect->width,
+					     rect->height);
 			hitfb_accel_start(0);
 		}
 		hitfb_accel_wait();
@@ -171,23 +169,24 @@
 
 static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
 {
-	hitfb_accel_bitblt(p->var.bits_per_pixel==16,area->sx,area->sy,
-		area->dx,area->dy,area->width,area->height,0x00cc,0);
+	hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy,
+			   area->dx, area->dy, area->width, area->height,
+			   0x00cc, 0);
 	hitfb_accel_wait();
 }
 
 static int hitfb_pan_display(struct fb_var_screeninfo *var,
 			     struct fb_info *info)
 {
-    int xoffset = var->xoffset;
-    int yoffset = var->yoffset;
+	int xoffset = var->xoffset;
+	int yoffset = var->yoffset;
 
-    if (xoffset!=0)
+	if (xoffset != 0)
 		return -EINVAL;
 
-    hitfb_set_base(yoffset*2*640);
+	fb_writew(yoffset, HD64461_LCDCBAR);
 
-    return 0;
+	return 0;
 }
 
 int hitfb_blank(int blank_mode, struct fb_info *info)
@@ -195,6 +194,12 @@
 	unsigned short v;
 
 	if (blank_mode) {
+#ifdef MACH_HP600
+		sh_dac_disable(DAC_LCD_BRIGHTNESS);
+		v = fb_readw(HD64461_GPBDR);
+		v |= HD64461_GPBDR_LCDOFF;
+		fb_writew(v, HD64461_GPBDR);
+#endif
 		v = fb_readw(HD64461_LDR1);
 		v &= ~HD64461_LDR1_DON;
 		fb_writew(v, HD64461_LDR1);
@@ -210,7 +215,12 @@
 		v = fb_readw(HD64461_STBCR);
 		v &= ~HD64461_STBCR_SLCDST;
 		fb_writew(v, HD64461_STBCR);
-
+#ifdef MACH_HP600
+		sh_dac_enable(DAC_LCD_BRIGHTNESS);
+		v = fb_readw(HD64461_GPBDR);
+		v &= ~HD64461_GPBDR_LCDOFF;
+		fb_writew(v, HD64461_GPBDR);
+#endif
 		v = fb_readw(HD64461_LDR1);
 		v |= HD64461_LDR1_DON;
 		fb_writew(v, HD64461_LDR1);
@@ -219,36 +229,71 @@
 		v &= ~HD64461_LCDCCR_MOFF;
 		fb_writew(v, HD64461_LCDCCR);
 	}
-
 	return 0;
 }
 
 static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-			   unsigned blue, unsigned transp,
-			   struct fb_info *info)
+			   unsigned blue, unsigned transp, struct fb_info *info)
 {
 	if (regno >= info->cmap.len)
 		return 1;
-    
+
 	switch (info->var.bits_per_pixel) {
-		case 8:
-			fb_writew(regno << 8, HD64461_CPTWAR);
-			fb_writew(red >> 10, HD64461_CPTWDR);
-			fb_writew(green >> 10, HD64461_CPTWDR);
-			fb_writew(blue >> 10, HD64461_CPTWDR);
-			break;
-		case 16:
-			((u32*)(info->pseudo_palette))[regno] =
-					((red   & 0xf800)      ) |
-					((green & 0xfc00) >>  5) |
-					((blue  & 0xf800) >> 11);
-			break;
+	case 8:
+		fb_writew(regno << 8, HD64461_CPTWAR);
+		fb_writew(red >> 10, HD64461_CPTWDR);
+		fb_writew(green >> 10, HD64461_CPTWDR);
+		fb_writew(blue >> 10, HD64461_CPTWDR);
+		break;
+	case 16:
+		((u32 *) (info->pseudo_palette))[regno] =
+		    ((red & 0xf800)) |
+		    ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+		break;
 	}
 	return 0;
 }
 
-static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+static struct fb_ops hitfb_ops = {
+	.owner 			= THIS_MODULE,
+	.fb_setcolreg 	= hitfb_setcolreg,
+	.fb_blank 		= hitfb_blank,
+	.fb_pan_display = hitfb_pan_display,
+	.fb_fillrect 	= hitfb_fillrect,
+	.fb_copyarea 	= hitfb_copyarea,
+	.fb_imageblit 	= cfb_imageblit,
+	.fb_cursor 		= soft_cursor,
+};
+
+int __init hitfb_init(void)
 {
+	unsigned short lcdclor, ldr3, ldvndr;
+	int size;
+
+	hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
+	hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024;
+
+	lcdclor = fb_readw(HD64461_LCDCLOR);
+	ldvndr = fb_readw(HD64461_LDVNDR);
+	ldr3 = fb_readw(HD64461_LDR3);
+
+	switch (ldr3 & 15) {
+	default:
+	case 4:
+		hitfb_var.bits_per_pixel = 8;
+		hitfb_var.xres = lcdclor;
+		break;
+	case 8:
+		hitfb_var.bits_per_pixel = 16;
+		hitfb_var.xres = lcdclor / 2;
+		break;
+	}
+	hitfb_fix.line_length = lcdclor;
+	hitfb_fix.visual = (hitfb_var.bits_per_pixel == 8) ?
+	    FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	hitfb_var.yres = ldvndr + 1;
+	hitfb_var.xres_virtual = hitfb_var.xres;
+	hitfb_var.yres_virtual = hitfb_fix.smem_len / lcdclor;
 	switch (hitfb_var.bits_per_pixel) {
 	case 8:
 		hitfb_var.red.offset = 0;
@@ -260,7 +305,7 @@
 		hitfb_var.transp.offset = 0;
 		hitfb_var.transp.length = 0;
 		break;
-	case 16:	/* RGB 565 */
+	case 16:		/* RGB 565 */
 		hitfb_var.red.offset = 11;
 		hitfb_var.red.length = 5;
 		hitfb_var.green.offset = 5;
@@ -272,70 +317,22 @@
 		break;
 	}
 
-	return 0;
-}
+	fb_info.fbops = &hitfb_ops;
+	fb_info.var = hitfb_var;
+	fb_info.fix = hitfb_fix;
+	fb_info.pseudo_palette = pseudo_palette;
+	fb_info.flags = FBINFO_FLAG_DEFAULT;
 
-static struct fb_ops hitfb_ops = {
-	.owner		= THIS_MODULE,
-	.fb_check_var	= hitfb_check_var,
-	.fb_set_par	= hitfb_set_par,
-	.fb_setcolreg	= hitfb_setcolreg,
-	.fb_pan_display = hitfb_pan_display,
-	.fb_blank	= hitfb_blank,
-	.fb_fillrect	= hitfb_fillrect,
-	.fb_copyarea	= hitfb_copyarea,
-	.fb_imageblit	= cfb_imageblit,
-	.fb_cursor	= soft_cursor,
-};
-
-int __init hitfb_init(void)
-{
-	unsigned short lcdclor, ldr3, ldvndr;
-	int size;
-
-	hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
-	hitfb_fix.smem_len = (MACH_HP690) ? 1024*1024 : 512*1024;
-
-	lcdclor = inw(HD64461_LCDCLOR);
-	ldvndr = inw(HD64461_LDVNDR);
-	ldr3 = inw(HD64461_LDR3);
-
-	switch (ldr3&15) {
-		default:
-		case 4:
-			hitfb_var.bits_per_pixel = 8;
-			hitfb_var.xres = lcdclor;
-			break;
-		case 8:
-			hitfb_var.bits_per_pixel = 16;
-			hitfb_var.xres = lcdclor/2;
-			break;
-	}
-
-	/* XXX: Most of this should go into hitfb_set_par().. --PFM. */
-	hitfb_fix.line_length = lcdclor;
-	hitfb_fix.visual = (hitfb_var.bits_per_pixel == 8) ?
-		FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
-	hitfb_var.yres = ldvndr+1;
-	hitfb_var.xres_virtual = hitfb_var.xres;
-	hitfb_var.yres_virtual = hitfb_fix.smem_len/lcdclor;
-
-	fb_info.fbops 		= &hitfb_ops;
-	fb_info.var 		= hitfb_var;
-	fb_info.fix 		= hitfb_fix;
-	fb_info.pseudo_palette 	= pseudo_palette;	
-	fb_info.flags 		= FBINFO_FLAG_DEFAULT;
-    	
-	fb_info.screen_base = (void *) hitfb_fix.smem_start;
+	fb_info.screen_base = (void *)hitfb_fix.smem_start;
 
 	size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16;
-	fb_alloc_cmap(&fb_info.cmap, size, 0); 	
+	fb_alloc_cmap(&fb_info.cmap, size, 0);
 
 	if (register_framebuffer(&fb_info) < 0)
 		return -EINVAL;
-    
+
 	printk(KERN_INFO "fb%d: %s frame buffer device\n",
-			fb_info.node, fb_info.fix.id);
+	       fb_info.node, fb_info.fix.id);
 	return 0;
 }
 
@@ -350,4 +347,3 @@
 #endif
 
 MODULE_LICENSE("GPL");
-
diff -Nru a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
--- a/drivers/video/i810/i810_main.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/video/i810/i810_main.c	Sat Apr  3 19:38:42 2004
@@ -281,7 +281,7 @@
 static void i810_load_2d(struct i810fb_par *par)
 {
 	u32 tmp;
-	u8 tmp8, *mmio = par->mmio_start_virtual;;
+	u8 tmp8, *mmio = par->mmio_start_virtual;
 
   	i810_writel(FW_BLC, mmio, par->watermark); 
 	tmp = i810_readl(PIXCONF, mmio);
diff -Nru a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h
--- a/drivers/video/i810/i810_main.h	Sat Apr  3 19:38:44 2004
+++ b/drivers/video/i810/i810_main.h	Sat Apr  3 19:38:44 2004
@@ -84,7 +84,7 @@
 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 -Nru a/drivers/video/modedb.c b/drivers/video/modedb.c
--- a/drivers/video/modedb.c	Sat Apr  3 19:38:43 2004
+++ b/drivers/video/modedb.c	Sat Apr  3 19:38:43 2004
@@ -39,7 +39,7 @@
 
 #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 @@
 	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 @@
 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 __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 @@
     return 0;
 }
 
-EXPORT_SYMBOL(__fb_try_mode);
 EXPORT_SYMBOL(vesa_modes);
+EXPORT_SYMBOL(fb_find_mode);
diff -Nru a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
--- a/drivers/video/pm2fb.c	Sat Apr  3 19:38:56 2004
+++ b/drivers/video/pm2fb.c	Sat Apr  3 19:38:57 2004
@@ -434,14 +434,14 @@
 	pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
 }
 
-static void set_aperture(struct pm2fb_par* p)
+static void set_aperture(struct pm2fb_par* p, u32 depth)
 {
 	WAIT_FIFO(p, 4);
 #ifdef __LITTLE_ENDIAN
 	pm2_WR(p, PM2R_APERTURE_ONE, 0);
 	pm2_WR(p, PM2R_APERTURE_TWO, 0);
 #else
-	switch (p->depth) {
+	switch (depth) {
 	case 8:
 	case 24:
 		pm2_WR(p, PM2R_APERTURE_ONE, 0);
@@ -744,7 +744,7 @@
 		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
 	}
     
-	set_aperture(par);
+	set_aperture(par, depth);
     
 	DEFRW();
 	WAIT_FIFO(par, 19);
diff -Nru a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
--- a/drivers/video/pvr2fb.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/video/pvr2fb.c	Sat Apr  3 19:38:41 2004
@@ -338,6 +338,7 @@
 		      ((blue  & 0xf800) >> 11);
 
 		pvr2fb_set_pal_entry(par, regno, tmp);
+		((u16*)(info->pseudo_palette))[regno] = tmp;
 		break;
 	    case 24: /* RGB 888 */
 		red >>= 8; green >>= 8; blue >>= 8;
@@ -348,6 +349,7 @@
 		tmp = (transp << 24) | (red << 16) | (green << 8) | blue;
 
 		pvr2fb_set_pal_entry(par, regno, tmp);
+		((u32*)(info->pseudo_palette))[regno] = tmp;
 		break;
 	    default:
 		pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel);
diff -Nru a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
--- a/drivers/video/sa1100fb.c	Sat Apr  3 19:38:42 2004
+++ b/drivers/video/sa1100fb.c	Sat Apr  3 19:38:42 2004
@@ -1595,12 +1595,18 @@
 	 * of the framebuffer.
 	 */
 	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
-	fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
-					&fbi->map_dma, PTE_BUFFERABLE);
+	fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
+					      &fbi->map_dma, GFP_KERNEL);
 
 	if (fbi->map_cpu) {
 		fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
 		fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+		/*
+		 * FIXME: this is actually the wrong thing to place in
+		 * smem_start.  But fbdev suffers from the problem that
+		 * it needs an API which doesn't exist (in this case,
+		 * dma_writecombine_mmap)
+		 */
 		fbi->fb.fix.smem_start = fbi->screen_dma;
 	}
 
@@ -1613,7 +1619,7 @@
 };
 
 
-static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
+static struct sa1100fb_info * __init sa1100fb_init_fbinfo(struct device *dev)
 {
 	struct sa1100fb_mach_info *inf;
 	struct sa1100fb_info *fbi;
@@ -1624,6 +1630,7 @@
 		return NULL;
 
 	memset(fbi, 0, sizeof(struct sa1100fb_info));
+	fbi->dev = dev;
 
 	strcpy(fbi->fb.fix.id, SA1100_NAME);
 
@@ -1703,7 +1710,7 @@
 	if (!request_mem_region(0xb0100000, 0x10000, "LCD"))
 		return -EBUSY;
 
-	fbi = sa1100fb_init_fbinfo();
+	fbi = sa1100fb_init_fbinfo(dev);
 	ret = -ENOMEM;
 	if (!fbi)
 		goto failed;
diff -Nru a/drivers/video/sa1100fb.h b/drivers/video/sa1100fb.h
--- a/drivers/video/sa1100fb.h	Sat Apr  3 19:38:45 2004
+++ b/drivers/video/sa1100fb.h	Sat Apr  3 19:38:45 2004
@@ -63,6 +63,7 @@
 
 struct sa1100fb_info {
 	struct fb_info		fb;
+	struct device		*dev;
 	struct sa1100fb_rgb	*rgb[NR_RGB];
 
 	u_int			max_bpp;
diff -Nru a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
--- a/drivers/video/sis/init301.c	Sat Apr  3 19:38:41 2004
+++ b/drivers/video/sis/init301.c	Sat Apr  3 19:38:41 2004
@@ -2313,7 +2313,7 @@
 
 #ifdef SIS315H
 
-        unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01);;
+        unsigned char bridgerev = SiS_GetReg(SiS_Pr->SiS_Part4Port,0x01);
 
 	/* The following is nearly unpreditable and varies from machine
 	 * to machine. Especially the 301DH seems to be a real trouble
diff -Nru a/drivers/video/tgafb.c b/drivers/video/tgafb.c
--- a/drivers/video/tgafb.c	Sat Apr  3 19:38:54 2004
+++ b/drivers/video/tgafb.c	Sat Apr  3 19:38:54 2004
@@ -25,6 +25,7 @@
 #include <linux/pci.h>
 #include <asm/io.h>
 #include <video/tgafb.h>
+#include <linux/selection.h>
 
 /*
  * Local functions.
diff -Nru a/fs/Kconfig b/fs/Kconfig
--- a/fs/Kconfig	Sat Apr  3 19:38:44 2004
+++ b/fs/Kconfig	Sat Apr  3 19:38:44 2004
@@ -866,7 +866,7 @@
 
 config HUGETLBFS
 	bool "HugeTLB file system support"
-	depends X86 || IA64 || PPC64 || SPARC64 || X86_64 || BROKEN
+	depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || X86_64 || BROKEN
 
 config HUGETLB_PAGE
 	def_bool HUGETLBFS
@@ -1227,6 +1227,9 @@
 	  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 +1305,18 @@
 	  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 +1425,24 @@
 	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.)"
@@ -1585,7 +1587,7 @@
 #
 config INTERMEZZO_FS
 	tristate "InterMezzo file system support (replicating fs) (EXPERIMENTAL)"
-	depends on INET && EXPERIMENTAL && BROKEN
+	depends on INET && EXPERIMENTAL 
 	help
 	  InterMezzo is a networked file system with disconnected operation
 	  and kernel level write back caching.  It is most often used for
diff -Nru a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
--- a/fs/Kconfig.binfmt	Sat Apr  3 19:38:55 2004
+++ b/fs/Kconfig.binfmt	Sat Apr  3 19:38:55 2004
@@ -44,7 +44,7 @@
 
 config BINFMT_AOUT
 	tristate "Kernel support for a.out and ECOFF binaries"
-	depends on (X86 && !X86_64) || ALPHA || ARM || M68K || MIPS || SPARC
+	depends on (X86 && !X86_64) || ALPHA || ARM || M68K || MIPS || SPARC32
 	---help---
 	  A.out (Assembler.OUTput) is a set of formats for libraries and
 	  executables used in the earliest versions of UNIX.  Linux used
@@ -99,7 +99,7 @@
 	---help---
 	  If you say Y here, it will be possible to plug wrapper-driven binary
 	  formats into the kernel. You will like this especially when you use
-	  programs that need an interpreter to run like Java, Python or
+	  programs that need an interpreter to run like Java, Python, .NET or
 	  Emacs-Lisp. It's also useful if you often run DOS executables under
 	  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from
 	  <http://www.tldp.org/docs.html#howto>). Once you have
@@ -109,8 +109,9 @@
 
 	  You can do other nice things, too. Read the file
 	  <file:Documentation/binfmt_misc.txt> to learn how to use this
-	  feature, and <file:Documentation/java.txt> for information about how
-	  to include Java support.
+	  feature, <file:Documentation/java.txt> for information about how
+	  to include Java support. and <file:Documentation/mono.txt> for
+          information about how to include Mono-based .NET support.
 
           To use binfmt_misc, you will need to mount it:
 		mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
diff -Nru a/fs/adfs/super.c b/fs/adfs/super.c
--- a/fs/adfs/super.c	Sat Apr  3 19:38:40 2004
+++ b/fs/adfs/super.c	Sat Apr  3 19:38:40 2004
@@ -335,6 +335,8 @@
 	struct adfs_sb_info *asb;
 	struct inode *root;
 
+	sb->s_flags |= MS_NODIRATIME;
+
 	asb = kmalloc(sizeof(*asb), GFP_KERNEL);
 	if (!asb)
 		return -ENOMEM;
diff -Nru a/fs/affs/super.c b/fs/affs/super.c
--- a/fs/affs/super.c	Sat Apr  3 19:38:45 2004
+++ b/fs/affs/super.c	Sat Apr  3 19:38:45 2004
@@ -293,6 +293,7 @@
 
 	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 -Nru a/fs/afs/inode.c b/fs/afs/inode.c
--- a/fs/afs/inode.c	Sat Apr  3 19:38:42 2004
+++ b/fs/afs/inode.c	Sat Apr  3 19:38:42 2004
@@ -188,6 +188,7 @@
 #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 -Nru a/fs/afs/super.c b/fs/afs/super.c
--- a/fs/afs/super.c	Sat Apr  3 19:38:43 2004
+++ b/fs/afs/super.c	Sat Apr  3 19:38:43 2004
@@ -53,6 +53,7 @@
 	.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 -Nru a/fs/aio.c b/fs/aio.c
--- a/fs/aio.c	Sat Apr  3 19:38:43 2004
+++ b/fs/aio.c	Sat Apr  3 19:38:43 2004
@@ -798,8 +798,8 @@
 
 static int read_events(struct kioctx *ctx,
 			long min_nr, long nr,
-			struct io_event *event,
-			struct timespec *timeout)
+			struct io_event __user *event,
+			struct timespec __user *timeout)
 {
 	long			start_jiffies = jiffies;
 	struct task_struct	*tsk = current;
@@ -991,7 +991,7 @@
 	struct kiocb *req;
 	struct file *file;
 	ssize_t ret;
-	char *buf;
+	char __user *buf;
 
 	/* enforce forwards compatibility on users */
 	if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
@@ -1032,7 +1032,7 @@
 	req->ki_user_data = iocb->aio_data;
 	req->ki_pos = iocb->aio_offset;
 
-	buf = (char *)(unsigned long)iocb->aio_buf;
+	buf = (char __user *)(unsigned long)iocb->aio_buf;
 
 	switch (iocb->aio_lio_opcode) {
 	case IOCB_CMD_PREAD:
@@ -1148,7 +1148,7 @@
  *	Finds a given iocb for cancellation.
  *	MUST be called with ctx->ctx_lock held.
  */
-struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb *iocb, u32 key)
+struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb, u32 key)
 {
 	struct list_head *pos;
 	/* TODO: use a hash or array, this sucks. */
@@ -1170,8 +1170,8 @@
  *	invalid.  May fail with -EAGAIN if the iocb specified was not
  *	cancelled.  Will fail with -ENOSYS if not implemented.
  */
-asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb *iocb,
-			      struct io_event *result)
+asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb,
+			      struct io_event __user *result)
 {
 	int (*cancel)(struct kiocb *iocb, struct io_event *res);
 	struct kioctx *ctx;
@@ -1234,17 +1234,15 @@
 asmlinkage long sys_io_getevents(aio_context_t ctx_id,
 				 long min_nr,
 				 long nr,
-				 struct io_event *events,
-				 struct timespec *timeout)
+				 struct io_event __user *events,
+				 struct timespec __user *timeout)
 {
 	struct kioctx *ioctx = lookup_ioctx(ctx_id);
 	long ret = -EINVAL;
 
-	if (unlikely(min_nr > nr || min_nr < 0 || nr < 0))
-		return ret;
-
-	if (likely(NULL != ioctx)) {
-		ret = read_events(ioctx, min_nr, nr, events, timeout);
+	if (likely(ioctx)) {
+		if (likely(min_nr <= nr && min_nr >= 0 && nr >= 0))
+			ret = read_events(ioctx, min_nr, nr, events, timeout);
 		put_ioctx(ioctx);
 	}
 
diff -Nru a/fs/bfs/dir.c b/fs/bfs/dir.c
--- a/fs/bfs/dir.c	Sat Apr  3 19:38:55 2004
+++ b/fs/bfs/dir.c	Sat Apr  3 19:38:55 2004
@@ -65,7 +65,6 @@
 		brelse(bh);
 	}
 
-	update_atime(dir);
 	unlock_kernel();
 	return 0;	
 }
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c	Sat Apr  3 19:38:43 2004
+++ b/fs/binfmt_elf.c	Sat Apr  3 19:38:43 2004
@@ -830,9 +830,8 @@
 		   and some applications "depend" upon this behavior.
 		   Since we do not have the power to recompile these, we
 		   emulate the SVr4 behavior.  Sigh.  */
-		/* N.B. Shouldn't the size here be PAGE_SIZE?? */
 		down_write(&current->mm->mmap_sem);
-		error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
+		error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE, 0);
 		up_write(&current->mm->mmap_sem);
 	}
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Sat Apr  3 19:38:44 2004
+++ b/fs/bio.c	Sat Apr  3 19:38:44 2004
@@ -701,11 +701,12 @@
 {
 	struct bio_pair *bp = container_of(bi, struct bio_pair, bio1);
 
-	if (bi->bi_size)
-		return 1;
 	if (err)
 		bp->error = err;
 
+	if (bi->bi_size)
+		return 1;
+
 	bio_pair_release(bp);
 	return 0;
 }
@@ -714,10 +715,11 @@
 {
 	struct bio_pair *bp = container_of(bi, struct bio_pair, bio2);
 
-	if (bi->bi_size)
-		return 1;
 	if (err)
 		bp->error = err;
+
+	if (bi->bi_size)
+		return 1;
 
 	bio_pair_release(bp);
 	return 0;
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Sat Apr  3 19:38:57 2004
+++ b/fs/block_dev.c	Sat Apr  3 19:38:57 2004
@@ -116,9 +116,18 @@
 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);
@@ -522,7 +531,7 @@
 
 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 @@
 	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)
 {
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Sat Apr  3 19:38:44 2004
+++ b/fs/buffer.c	Sat Apr  3 19:38:44 2004
@@ -3024,6 +3024,26 @@
 	}
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static void buffer_exit_cpu(int cpu)
+{
+	int i;
+	struct bh_lru *b = &per_cpu(bh_lrus, cpu);
+
+	for (i = 0; i < BH_LRU_SIZE; i++) {
+		brelse(b->bhs[i]);
+		b->bhs[i] = NULL;
+	}
+}
+
+static int buffer_cpu_notify(struct notifier_block *self,
+			      unsigned long action, void *hcpu)
+{
+	if (action == CPU_DEAD)
+		buffer_exit_cpu((unsigned long)hcpu);
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
 
 void __init buffer_init(void)
 {
@@ -3041,6 +3061,7 @@
 	 */
 	nrpages = (nr_free_buffer_pages() * 10) / 100;
 	max_buffer_heads = nrpages * (PAGE_SIZE / sizeof(struct buffer_head));
+	hotcpu_notifier(buffer_cpu_notify, 0);
 }
 
 EXPORT_SYMBOL(__bforget);
diff -Nru a/fs/char_dev.c b/fs/char_dev.c
--- a/fs/char_dev.c	Sat Apr  3 19:38:42 2004
+++ b/fs/char_dev.c	Sat Apr  3 19:38:42 2004
@@ -265,7 +265,7 @@
 		spin_unlock(&cdev_lock);
 		kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
 		if (!kobj)
-			return -ENODEV;
+			return -ENXIO;
 		new = container_of(kobj, struct cdev, kobj);
 		spin_lock(&cdev_lock);
 		p = inode->i_cdev;
@@ -275,9 +275,9 @@
 			list_add(&inode->i_devices, &p->list);
 			new = NULL;
 		} else if (!cdev_get(p))
-			ret = -ENODEV;
+			ret = -ENXIO;
 	} else if (!cdev_get(p))
-		ret = -ENODEV;
+		ret = -ENXIO;
 	spin_unlock(&cdev_lock);
 	cdev_put(new);
 	if (ret)
@@ -285,7 +285,7 @@
 	filp->f_op = fops_get(p->ops);
 	if (!filp->f_op) {
 		cdev_put(p);
-		return -ENODEV;
+		return -ENXIO;
 	}
 	if (filp->f_op->open) {
 		lock_kernel();
@@ -340,15 +340,9 @@
 
 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 @@
 void cdev_del(struct cdev *p)
 {
 	cdev_unmap(p->dev, p->count);
-	kobject_del(&p->kobj);
 	kobject_put(&p->kobj);
 }
 
@@ -407,18 +400,12 @@
 	.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 @@
 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 @@
 
 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 -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
--- a/fs/cifs/cifsfs.c	Sat Apr  3 19:38:43 2004
+++ b/fs/cifs/cifsfs.c	Sat Apr  3 19:38:43 2004
@@ -77,6 +77,7 @@
 	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 -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c
--- a/fs/cifs/connect.c	Sat Apr  3 19:38:55 2004
+++ b/fs/cifs/connect.c	Sat Apr  3 19:38:55 2004
@@ -116,7 +116,7 @@
 	if(server->ssocket) {
 		cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
 			server->ssocket->flags));
-		server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);;
+		server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
 		cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
 			server->ssocket->flags));
 		sock_release(server->ssocket);
diff -Nru a/fs/coda/dir.c b/fs/coda/dir.c
--- a/fs/coda/dir.c	Sat Apr  3 19:38:41 2004
+++ b/fs/coda/dir.c	Sat Apr  3 19:38:41 2004
@@ -510,8 +510,10 @@
 			goto out;
 
 		ret = -ENOENT;
-		if (!IS_DEADDIR(host_inode))
+		if (!IS_DEADDIR(host_inode)) {
 			ret = host_file->f_op->readdir(host_file, filldir, dirent);
+			file_accessed(host_file);
+		}
 	}
 out:
 	coda_file->f_pos = host_file->f_pos;
diff -Nru a/fs/coda/inode.c b/fs/coda/inode.c
--- a/fs/coda/inode.c	Sat Apr  3 19:38:43 2004
+++ b/fs/coda/inode.c	Sat Apr  3 19:38:43 2004
@@ -171,6 +171,7 @@
 	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 @@
 	.name		= "coda",
 	.get_sb		= coda_get_sb,
 	.kill_sb	= kill_anon_super,
+	.fs_flags	= FS_BINARY_MOUNTDATA,
 };
 
diff -Nru a/fs/compat.c b/fs/compat.c
--- a/fs/compat.c	Sat Apr  3 19:38:43 2004
+++ b/fs/compat.c	Sat Apr  3 19:38:43 2004
@@ -27,6 +27,9 @@
 #include <linux/ioctl32.h>
 #include <linux/init.h>
 #include <linux/sockios.h>	/* for SIOCDEVPRIVATE */
+#include <linux/smb.h>
+#include <linux/smb_mount.h>
+#include <linux/ncp_mount.h>
 #include <linux/smp_lock.h>
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
@@ -642,3 +645,152 @@
 		ret = sys_io_submit(ctx_id, nr, iocb64);
 	return ret;
 }
+
+struct compat_ncp_mount_data {
+	compat_int_t version;
+	compat_uint_t ncp_fd;
+	compat_uid_t mounted_uid;
+	compat_pid_t wdog_pid;
+	unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
+	compat_uint_t time_out;
+	compat_uint_t retry_count;
+	compat_uint_t flags;
+	compat_uid_t uid;
+	compat_gid_t gid;
+	compat_mode_t file_mode;
+	compat_mode_t dir_mode;
+};
+
+struct compat_ncp_mount_data_v4 {
+	compat_int_t version;
+	compat_ulong_t flags;
+	compat_ulong_t mounted_uid;
+	compat_long_t wdog_pid;
+	compat_uint_t ncp_fd;
+	compat_uint_t time_out;
+	compat_uint_t retry_count;
+	compat_ulong_t uid;
+	compat_ulong_t gid;
+	compat_ulong_t file_mode;
+	compat_ulong_t dir_mode;
+};
+
+static void *do_ncp_super_data_conv(void *raw_data)
+{
+	int version = *(unsigned int *)raw_data;
+
+	if (version == 3) {
+		struct compat_ncp_mount_data *c_n = raw_data;
+		struct ncp_mount_data *n = raw_data;
+
+		n->dir_mode = c_n->dir_mode;
+		n->file_mode = c_n->file_mode;
+		n->gid = c_n->gid;
+		n->uid = c_n->uid;
+		memmove (n->mounted_vol, c_n->mounted_vol, (sizeof (c_n->mounted_vol) + 3 * sizeof (unsigned int)));
+		n->wdog_pid = c_n->wdog_pid;
+		n->mounted_uid = c_n->mounted_uid;
+	} else if (version == 4) {
+		struct compat_ncp_mount_data_v4 *c_n = raw_data;
+		struct ncp_mount_data_v4 *n = raw_data;
+
+		n->dir_mode = c_n->dir_mode;
+		n->file_mode = c_n->file_mode;
+		n->gid = c_n->gid;
+		n->uid = c_n->uid;
+		n->retry_count = c_n->retry_count;
+		n->time_out = c_n->time_out;
+		n->ncp_fd = c_n->ncp_fd;
+		n->wdog_pid = c_n->wdog_pid;
+		n->mounted_uid = c_n->mounted_uid;
+		n->flags = c_n->flags;
+	} else if (version != 5) {
+		return NULL;
+	}
+
+	return raw_data;
+}
+
+struct compat_smb_mount_data {
+	compat_int_t version;
+	compat_uid_t mounted_uid;
+	compat_uid_t uid;
+	compat_gid_t gid;
+	compat_mode_t file_mode;
+	compat_mode_t dir_mode;
+};
+
+static void *do_smb_super_data_conv(void *raw_data)
+{
+	struct smb_mount_data *s = raw_data;
+	struct compat_smb_mount_data *c_s = raw_data;
+
+	if (c_s->version != SMB_MOUNT_OLDVERSION)
+		goto out;
+	s->dir_mode = c_s->dir_mode;
+	s->file_mode = c_s->file_mode;
+	s->gid = c_s->gid;
+	s->uid = c_s->uid;
+	s->mounted_uid = c_s->mounted_uid;
+ out:
+	return raw_data;
+}
+
+extern int copy_mount_options (const void __user *, unsigned long *);
+
+#define SMBFS_NAME      "smbfs"
+#define NCPFS_NAME      "ncpfs"
+
+asmlinkage int compat_sys_mount(char __user * dev_name, char __user * dir_name,
+				char __user * type, unsigned long flags,
+				void __user * data)
+{
+	unsigned long type_page;
+	unsigned long data_page;
+	unsigned long dev_page;
+	char *dir_page;
+	int retval;
+
+	retval = copy_mount_options (type, &type_page);
+	if (retval < 0)
+		goto out;
+
+	dir_page = getname(dir_name);
+	retval = PTR_ERR(dir_page);
+	if (IS_ERR(dir_page))
+		goto out1;
+
+	retval = copy_mount_options (dev_name, &dev_page);
+	if (retval < 0)
+		goto out2;
+
+	retval = copy_mount_options (data, &data_page);
+	if (retval < 0)
+		goto out3;
+
+	retval = -EINVAL;
+
+	if (type_page) {
+		if (!strcmp((char *)type_page, SMBFS_NAME)) {
+			do_smb_super_data_conv((void *)data_page);
+		} else if (!strcmp((char *)type_page, NCPFS_NAME)) {
+			do_ncp_super_data_conv((void *)data_page);
+		}
+	}
+
+	lock_kernel();
+	retval = do_mount((char*)dev_page, dir_page, (char*)type_page,
+			flags, (void*)data_page);
+	unlock_kernel();
+
+	free_page(data_page);
+ out3:
+	free_page(dev_page);
+ out2:
+	putname(dir_page);
+ out1:
+	free_page(type_page);
+ out:
+	return retval;
+}
+
diff -Nru a/fs/compat_ioctl.c b/fs/compat_ioctl.c
--- a/fs/compat_ioctl.c	Sat Apr  3 19:38:56 2004
+++ b/fs/compat_ioctl.c	Sat Apr  3 19:38:56 2004
@@ -1952,6 +1952,7 @@
 		set_fs (KERNEL_DS);
 		err = sys_ioctl(fd, cmd, (unsigned long)&a);
 		set_fs (old_fs);
+		break;
 	default:
 		return -EINVAL;
 	}                                        
@@ -1985,13 +1986,18 @@
 }
 
 /* Bluetooth ioctls */
-#define HCIUARTSETPROTO        _IOW('U', 200, int)
-#define HCIUARTGETPROTO        _IOR('U', 201, int)
+#define HCIUARTSETPROTO	_IOW('U', 200, int)
+#define HCIUARTGETPROTO	_IOR('U', 201, int)
 
-#define BNEPCONNADD    _IOW('B', 200, int)
-#define BNEPCONNDEL    _IOW('B', 201, int)
-#define BNEPGETCONNLIST        _IOR('B', 210, int)
-#define BNEPGETCONNINFO        _IOR('B', 211, int)
+#define BNEPCONNADD	_IOW('B', 200, int)
+#define BNEPCONNDEL	_IOW('B', 201, int)
+#define BNEPGETCONNLIST	_IOR('B', 210, int)
+#define BNEPGETCONNINFO	_IOR('B', 211, int)
+
+#define CMTPCONNADD	_IOW('C', 200, int)
+#define CMTPCONNDEL	_IOW('C', 201, int)
+#define CMTPGETCONNLIST	_IOR('C', 210, int)
+#define CMTPGETCONNINFO	_IOR('C', 211, int)
 
 struct floppy_struct32 {
 	compat_uint_t	size;
@@ -3064,6 +3070,20 @@
 	return sys_ioctl(fd, cmd, (unsigned long) iwr);
 }
 
+/* Emulate old style bridge ioctls */
+static int do_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	u32 tmp;
+	unsigned long *argbuf = compat_alloc_user_space(3 * sizeof(unsigned long)); 
+	int i;	
+	for (i = 0; i < 3; i++) {
+		if (get_user(tmp, i + ((u32 *)arg)) ||
+		    put_user(tmp, i + argbuf))
+			return -EFAULT;
+	}
+	return sys_ioctl(fd, cmd, (unsigned long)argbuf);
+}
+
 #undef CODE
 #endif
 
@@ -3241,6 +3261,8 @@
 HANDLE_IOCTL(SIOCGIWNICKN, do_wireless_ioctl)
 HANDLE_IOCTL(SIOCSIWENCODE, do_wireless_ioctl)
 HANDLE_IOCTL(SIOCGIWENCODE, do_wireless_ioctl)
+HANDLE_IOCTL(SIOCSIFBR, do_bridge_ioctl)
+HANDLE_IOCTL(SIOCGIFBR, do_bridge_ioctl)
 
 #undef DECLARES
 #endif
diff -Nru a/fs/cramfs/inode.c b/fs/cramfs/inode.c
--- a/fs/cramfs/inode.c	Sat Apr  3 19:38:41 2004
+++ b/fs/cramfs/inode.c	Sat Apr  3 19:38:41 2004
@@ -201,6 +201,8 @@
 	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 -Nru a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
--- a/fs/exportfs/expfs.c	Sat Apr  3 19:38:55 2004
+++ b/fs/exportfs/expfs.c	Sat Apr  3 19:38:55 2004
@@ -135,7 +135,6 @@
 	 * the noprogress counter.  If we go through the loop 10 times (2 is
 	 * probably enough) without getting anywhere, we just give up
 	 */
-	lock_kernel();
 	noprogress= 0;
 	while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) {
 		struct dentry *pd = target_dir;
@@ -232,7 +231,6 @@
 		/* something went wrong - oh-well */
 		if (!err)
 			err = -ESTALE;
-		unlock_kernel();
 		goto err_target;
 	}
 	/* if we weren't after a directory, have one more step to go */
@@ -254,7 +252,6 @@
 		}
 	}
 	dput(target_dir);
-	unlock_kernel();
 	/* now result is properly connected, it is our best bet */
 	if (acceptable(context, result))
 		return result;
diff -Nru a/fs/ext2/acl.c b/fs/ext2/acl.c
--- a/fs/ext2/acl.c	Sat Apr  3 19:38:55 2004
+++ b/fs/ext2/acl.c	Sat Apr  3 19:38:55 2004
@@ -154,10 +154,9 @@
 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 @@
 		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 -Nru a/fs/ext2/dir.c b/fs/ext2/dir.c
--- a/fs/ext2/dir.c	Sat Apr  3 19:38:43 2004
+++ b/fs/ext2/dir.c	Sat Apr  3 19:38:43 2004
@@ -310,7 +310,6 @@
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
 	filp->f_version = inode->i_version;
-	update_atime(inode);
 	return 0;
 }
 
diff -Nru a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
--- a/fs/ext2/ialloc.c	Sat Apr  3 19:38:43 2004
+++ b/fs/ext2/ialloc.c	Sat Apr  3 19:38:43 2004
@@ -294,7 +294,7 @@
 	ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter);
 
 	if ((parent == sb->s_root->d_inode) ||
-	    (parent->i_flags & EXT2_TOPDIR_FL)) {
+	    (EXT2_I(parent)->i_flags & EXT2_TOPDIR_FL)) {
 		struct ext2_group_desc *best_desc = NULL;
 		struct buffer_head *best_bh = NULL;
 		int best_ndir = inodes_per_group;
diff -Nru a/fs/ext3/acl.c b/fs/ext3/acl.c
--- a/fs/ext3/acl.c	Sat Apr  3 19:38:42 2004
+++ b/fs/ext3/acl.c	Sat Apr  3 19:38:42 2004
@@ -157,10 +157,9 @@
 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 @@
 		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 -Nru a/fs/ext3/dir.c b/fs/ext3/dir.c
--- a/fs/ext3/dir.c	Sat Apr  3 19:38:43 2004
+++ b/fs/ext3/dir.c	Sat Apr  3 19:38:43 2004
@@ -224,7 +224,6 @@
 		offset = 0;
 		brelse (bh);
 	}
-       update_atime(inode);
 out:
 	return ret;
 }
@@ -506,7 +505,6 @@
 	}
 finished:
 	info->last_pos = filp->f_pos;
-	update_atime(inode);
 	return 0;
 }
 
diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
--- a/fs/ext3/ialloc.c	Sat Apr  3 19:38:43 2004
+++ b/fs/ext3/ialloc.c	Sat Apr  3 19:38:43 2004
@@ -275,7 +275,7 @@
 	ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter);
 
 	if ((parent == sb->s_root->d_inode) ||
-	    (parent->i_flags & EXT3_TOPDIR_FL)) {
+	    (EXT3_I(parent)->i_flags & EXT3_TOPDIR_FL)) {
 		int best_ndir = inodes_per_group;
 		int best_group = -1;
 
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Sat Apr  3 19:38:43 2004
+++ b/fs/fat/inode.c	Sat Apr  3 19:38:43 2004
@@ -778,6 +778,7 @@
 	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 -Nru a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c	Sat Apr  3 19:38:45 2004
+++ b/fs/fcntl.c	Sat Apr  3 19:38:45 2004
@@ -293,11 +293,11 @@
 			err = dupfd(filp, arg);
 			break;
 		case F_GETFD:
-			err = get_close_on_exec(fd);
+			err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
 			break;
 		case F_SETFD:
 			err = 0;
-			set_close_on_exec(fd, arg&1);
+			set_close_on_exec(fd, arg & FD_CLOEXEC);
 			break;
 		case F_GETFL:
 			err = filp->f_flags;
diff -Nru a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
--- a/fs/freevxfs/vxfs_super.c	Sat Apr  3 19:38:55 2004
+++ b/fs/freevxfs/vxfs_super.c	Sat Apr  3 19:38:55 2004
@@ -145,6 +145,8 @@
 	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 -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c	Sat Apr  3 19:38:57 2004
+++ b/fs/fs-writeback.c	Sat Apr  3 19:38:57 2004
@@ -44,6 +44,13 @@
  *
  * This function *must* be atomic for the I_DIRTY_PAGES case -
  * set_page_dirty() is called under spinlock in several places.
+ *
+ * Note that for blockdevs, inode->dirtied_when represents the dirtying time of
+ * the block-special inode (/dev/hda1) itself.  And the ->dirtied_when field of
+ * the kernel-internal blockdev inode represents the dirtying time of the
+ * blockdev's pages.  This is why for I_DIRTY_PAGES we always use
+ * page->mapping->host, so the page-dirtying time is recorded in the internal
+ * blockdev inode.
  */
 void __mark_inode_dirty(struct inode *inode, int flags)
 {
@@ -71,7 +78,6 @@
 	spin_lock(&inode_lock);
 	if ((inode->i_state & flags) != flags) {
 		const int was_dirty = inode->i_state & I_DIRTY;
-		struct address_space *mapping = inode->i_mapping;
 
 		inode->i_state |= flags;
 
@@ -99,7 +105,7 @@
 		 * reposition it (that would break s_dirty time-ordering).
 		 */
 		if (!was_dirty) {
-			mapping->dirtied_when = jiffies;
+			inode->dirtied_when = jiffies;
 			list_move(&inode->i_list, &sb->s_dirty);
 		}
 	}
@@ -176,11 +182,11 @@
 		} else if (!list_empty(&mapping->dirty_pages)) {
 			/* Redirtied */
 			inode->i_state |= I_DIRTY_PAGES;
-			mapping->dirtied_when = jiffies;
+			inode->dirtied_when = jiffies;
 			list_move(&inode->i_list, &sb->s_dirty);
 		} else if (inode->i_state & I_DIRTY) {
 			/* Redirtied */
-			mapping->dirtied_when = jiffies;
+			inode->dirtied_when = jiffies;
 			list_move(&inode->i_list, &sb->s_dirty);
 		} else if (atomic_read(&inode->i_count)) {
 			list_move(&inode->i_list, &inode_in_use);
@@ -220,7 +226,7 @@
  * Write out a superblock's list of dirty inodes.  A wait will be performed
  * upon no inodes, all inodes or the final one, depending upon sync_mode.
  *
- * If older_than_this is non-NULL, then only write out mappings which
+ * If older_than_this is non-NULL, then only write out inodes which
  * had their first dirtying at a time earlier than *older_than_this.
  *
  * If we're a pdlfush thread, then implement pdflush collision avoidance
@@ -292,11 +298,11 @@
 		}
 
 		/* Was this inode dirtied after sync_sb_inodes was called? */
-		if (time_after(mapping->dirtied_when, start))
+		if (time_after(inode->dirtied_when, start))
 			break;
 
 		/* Was this inode dirtied too recently? */
-		if (wbc->older_than_this && time_after(mapping->dirtied_when,
+		if (wbc->older_than_this && time_after(inode->dirtied_when,
 						*wbc->older_than_this))
 			break;
 
@@ -308,7 +314,7 @@
 		__iget(inode);
 		__writeback_single_inode(inode, wbc);
 		if (wbc->sync_mode == WB_SYNC_HOLD) {
-			mapping->dirtied_when = jiffies;
+			inode->dirtied_when = jiffies;
 			list_move(&inode->i_list, &sb->s_dirty);
 		}
 		if (current_is_pdflush())
diff -Nru a/fs/hfs/super.c b/fs/hfs/super.c
--- a/fs/hfs/super.c	Sat Apr  3 19:38:42 2004
+++ b/fs/hfs/super.c	Sat Apr  3 19:38:42 2004
@@ -268,6 +268,7 @@
 	}
 
 	sb->s_op = &hfs_super_operations;
+	sb->s_flags |= MS_NODIRATIME;
 	init_MUTEX(&sbi->bitmap_lock);
 
 	res = hfs_mdb_get(sb);
diff -Nru a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c
--- a/fs/hpfs/alloc.c	Sat Apr  3 19:38:41 2004
+++ b/fs/hpfs/alloc.c	Sat Apr  3 19:38:41 2004
@@ -6,7 +6,6 @@
  *  HPFS bitmap operations
  */
 
-#include <linux/buffer_head.h>
 #include "hpfs_fn.h"
 
 /*
diff -Nru a/fs/hpfs/anode.c b/fs/hpfs/anode.c
--- a/fs/hpfs/anode.c	Sat Apr  3 19:38:41 2004
+++ b/fs/hpfs/anode.c	Sat Apr  3 19:38:41 2004
@@ -6,7 +6,6 @@
  *  handling HPFS anode tree that contains file allocation info
  */
 
-#include <linux/buffer_head.h>
 #include "hpfs_fn.h"
 
 /* Find a sector in allocation tree */
diff -Nru a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
--- a/fs/hpfs/buffer.c	Sat Apr  3 19:38:43 2004
+++ b/fs/hpfs/buffer.c	Sat Apr  3 19:38:43 2004
@@ -6,8 +6,6 @@
  *  general buffer i/o
  */
 
-#include <linux/buffer_head.h>
-#include <linux/string.h>
 #include "hpfs_fn.h"
 
 void hpfs_lock_creation(struct super_block *s)
@@ -26,108 +24,6 @@
 	up(&hpfs_sb(s)->hpfs_creation_de);
 }
 
-void hpfs_lock_iget(struct super_block *s, int mode)
-{
-#ifdef DEBUG_LOCKS
-	printk("lock iget\n");
-#endif
-	while (hpfs_sb(s)->sb_rd_inode) sleep_on(&hpfs_sb(s)->sb_iget_q);
-	hpfs_sb(s)->sb_rd_inode = mode;
-}
-
-void hpfs_unlock_iget(struct super_block *s)
-{
-#ifdef DEBUG_LOCKS
-	printk("unlock iget\n");
-#endif
-	hpfs_sb(s)->sb_rd_inode = 0;
-	wake_up(&hpfs_sb(s)->sb_iget_q);
-}
-
-void hpfs_lock_inode(struct inode *i)
-{
-	if (i) {
-		struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
-		down(&hpfs_inode->i_sem);
-	}
-}
-
-void hpfs_unlock_inode(struct inode *i)
-{
-	if (i) {
-		struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
-		up(&hpfs_inode->i_sem);
-	}
-}
-
-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,
@@ -174,7 +70,7 @@
 		return 0;
 	}
 
-	qbh->data = data = (char *)kmalloc(2048, GFP_KERNEL);
+	qbh->data = data = (char *)kmalloc(2048, GFP_NOFS);
 	if (!data) {
 		printk("HPFS: hpfs_map_4sectors: out of memory\n");
 		goto bail;
@@ -226,7 +122,7 @@
 	}
 
 	/*return hpfs_map_4sectors(s, secno, qbh, 0);*/
-	if (!(qbh->data = kmalloc(2048, GFP_KERNEL))) {
+	if (!(qbh->data = kmalloc(2048, GFP_NOFS))) {
 		printk("HPFS: hpfs_get_4sectors: out of memory\n");
 		return NULL;
 	}
diff -Nru a/fs/hpfs/dir.c b/fs/hpfs/dir.c
--- a/fs/hpfs/dir.c	Sat Apr  3 19:38:42 2004
+++ b/fs/hpfs/dir.c	Sat Apr  3 19:38:42 2004
@@ -7,11 +7,8 @@
  */
 
 #include "hpfs_fn.h"
-#include <linux/buffer_head.h>
-#include <linux/time.h>
-#include <linux/smp_lock.h>
 
-int hpfs_dir_release(struct inode *inode, struct file *filp)
+static int hpfs_dir_release(struct inode *inode, struct file *filp)
 {
 	lock_kernel();
 	hpfs_del_pos(inode, &filp->f_pos);
@@ -22,7 +19,7 @@
 
 /* This is slow, but it's not used often */
 
-loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
+static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
 {
 	loff_t new_off = off + (whence == 1 ? filp->f_pos : 0);
 	loff_t pos;
@@ -35,25 +32,25 @@
 
 	/*printk("dir lseek\n");*/
 	if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
-	hpfs_lock_inode(i);
+	down(&i->i_sem);
 	pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
 	while (pos != new_off) {
 		if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
 		else goto fail;
 		if (pos == 12) goto fail;
 	}
-	hpfs_unlock_inode(i);
-	ok:
+	up(&i->i_sem);
+ok:
 	unlock_kernel();
 	return filp->f_pos = new_off;
-	fail:
-	hpfs_unlock_inode(i);
+fail:
+	up(&i->i_sem);
 	/*printk("illegal lseek: %016llx\n", new_off);*/
 	unlock_kernel();
 	return -ESPIPE;
 }
 
-int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
@@ -109,8 +106,6 @@
 		goto out;
 	}
 	
-	hpfs_lock_inode(inode);
-	
 	while (1) {
 		again:
 		/* This won't work when cycle is longer than number of dirents
@@ -118,31 +113,23 @@
 		   maybe killall -9 ls helps */
 		if (hpfs_sb(inode->i_sb)->sb_chk)
 			if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) {
-				hpfs_unlock_inode(inode);
 				ret = -EFSERROR;
 				goto out;
 			}
-		if (filp->f_pos == 12) {
-			hpfs_unlock_inode(inode);
+		if (filp->f_pos == 12)
 			goto out;
-		}
 		if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) {
 			printk("HPFS: warning: pos==%d\n",(int)filp->f_pos);
-			hpfs_unlock_inode(inode);
 			goto out;
 		}
 		if (filp->f_pos == 0) {
-			if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) {
-				hpfs_unlock_inode(inode);
+			if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0)
 				goto out;
-			}
 			filp->f_pos = 11;
 		}
 		if (filp->f_pos == 11) {
-			if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0) {
-				hpfs_unlock_inode(inode);
+			if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0)
 				goto out;
-			}
 			filp->f_pos = 1;
 		}
 		if (filp->f_pos == 1) {
@@ -150,35 +137,28 @@
 			hpfs_add_pos(inode, &filp->f_pos);
 			filp->f_version = inode->i_version;
 		}
-			/*if (filp->f_version != inode->i_version) {
-				hpfs_unlock_inode(inode);
-				ret = -ENOENT;
-				goto out;
-			}*/	
-			old_pos = filp->f_pos;
-			if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
-				hpfs_unlock_inode(inode);
-				ret = -EIOERROR;
-				goto out;
-			}
-			if (de->first || de->last) {
-				if (hpfs_sb(inode->i_sb)->sb_chk) {
-					if (de->first && !de->last && (de->namelen != 2 || de ->name[0] != 1 || de->name[1] != 1)) hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08x", old_pos);
-					if (de->last && (de->namelen != 1 || de ->name[0] != 255)) hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08x", old_pos);
-				}
-				hpfs_brelse4(&qbh);
-				goto again;
-			}
-			tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
-			if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) {
-				filp->f_pos = old_pos;
-				if (tempname != (char *)de->name) kfree(tempname);
-				hpfs_brelse4(&qbh);
-				hpfs_unlock_inode(inode);
-				goto out;
+		old_pos = filp->f_pos;
+		if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) {
+			ret = -EIOERROR;
+			goto out;
+		}
+		if (de->first || de->last) {
+			if (hpfs_sb(inode->i_sb)->sb_chk) {
+				if (de->first && !de->last && (de->namelen != 2 || de ->name[0] != 1 || de->name[1] != 1)) hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08x", old_pos);
+				if (de->last && (de->namelen != 1 || de ->name[0] != 255)) hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08x", old_pos);
 			}
+			hpfs_brelse4(&qbh);
+			goto again;
+		}
+		tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
+		if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) {
+			filp->f_pos = old_pos;
 			if (tempname != (char *)de->name) kfree(tempname);
 			hpfs_brelse4(&qbh);
+			goto out;
+		}
+		if (tempname != (char *)de->name) kfree(tempname);
+		hpfs_brelse4(&qbh);
 	}
 out:
 	unlock_kernel();
@@ -220,7 +200,6 @@
 		goto end_add;
 	}
 
-	hpfs_lock_inode(dir);
 	/*
 	 * '.' and '..' will never be passed here.
 	 */
@@ -243,15 +222,28 @@
 	 * Go find or make an inode.
 	 */
 
-	hpfs_lock_iget(dir->i_sb, de->directory || (de->ea_size && hpfs_sb(dir->i_sb)->sb_eas) ? 1 : 2);
-	if (!(result = iget(dir->i_sb, ino))) {
-		hpfs_unlock_iget(dir->i_sb);
+	result = iget_locked(dir->i_sb, ino);
+	if (!result) {
 		hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode");
 		goto bail1;
 	}
+	if (result->i_state & I_NEW) {
+		hpfs_init_inode(result);
+		if (de->directory)
+			hpfs_read_inode(result);
+		else if (de->ea_size && hpfs_sb(dir->i_sb)->sb_eas)
+			hpfs_read_inode(result);
+		else {
+			result->i_mode |= S_IFREG;
+			result->i_mode &= ~0111;
+			result->i_op = &hpfs_file_iops;
+			result->i_fop = &hpfs_file_ops;
+			result->i_nlink = 1;
+		}
+		unlock_new_inode(result);
+	}
 	hpfs_result = hpfs_i(result);
 	if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino;
-	hpfs_unlock_iget(dir->i_sb);
 
 	hpfs_decide_conv(result, (char *)name, len);
 
@@ -299,7 +291,6 @@
 	 */
 
 	end:
-	hpfs_unlock_inode(dir);
 	end_add:
 	hpfs_set_dentry_operations(dentry);
 	unlock_kernel();
@@ -315,7 +306,15 @@
 	
 	/*bail:*/
 
-	hpfs_unlock_inode(dir);
 	unlock_kernel();
 	return ERR_PTR(-ENOENT);
 }
+
+struct file_operations hpfs_dir_ops =
+{
+	.llseek		= hpfs_dir_lseek,
+	.read		= generic_read_dir,
+	.readdir	= hpfs_readdir,
+	.release	= hpfs_dir_release,
+	.fsync		= hpfs_file_fsync,
+};
diff -Nru a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c
--- a/fs/hpfs/dnode.c	Sat Apr  3 19:38:43 2004
+++ b/fs/hpfs/dnode.c	Sat Apr  3 19:38:43 2004
@@ -6,7 +6,6 @@
  *  handling directory dnode tree - adding, deleteing & searching for dirents
  */
 
-#include <linux/buffer_head.h>
 #include "hpfs_fn.h"
 
 static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde)
@@ -32,7 +31,7 @@
 		for (; hpfs_inode->i_rddir_off[i]; i++)
 			if (hpfs_inode->i_rddir_off[i] == pos) return;
 	if (!(i&0x0f)) {
-		if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_KERNEL))) {
+		if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_NOFS))) {
 			printk("HPFS: out of memory for position list\n");
 			return;
 		}
@@ -236,7 +235,7 @@
 	struct buffer_head *bh;
 	struct fnode *fnode;
 	int c1, c2 = 0;
-	if (!(nname = kmalloc(256, GFP_KERNEL))) {
+	if (!(nname = kmalloc(256, GFP_NOFS))) {
 		printk("HPFS: out of memory, can't add to dnode\n");
 		return 1;
 	}
@@ -273,7 +272,7 @@
 		kfree(nname);
 		return 0;
 	}
-	if (!nd) if (!(nd = kmalloc(0x924, GFP_KERNEL))) {
+	if (!nd) if (!(nd = kmalloc(0x924, GFP_NOFS))) {
 		/* 0x924 is a max size of dnode after adding a dirent with
 		   max name length. We alloc this only once. There must
 		   not be any error while splitting dnodes, otherwise the
@@ -478,7 +477,7 @@
 	t = get_pos(dnode, de);
 	for_all_poss(i, hpfs_pos_subst, t, 4);
 	for_all_poss(i, hpfs_pos_subst, t + 1, 5);
-	if (!(nde = kmalloc(de->length, GFP_KERNEL))) {
+	if (!(nde = kmalloc(de->length, GFP_NOFS))) {
 		hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted");
 		hpfs_brelse4(&qbh);
 		return 0;
@@ -588,7 +587,7 @@
 		struct quad_buffer_head qbh1;
 		if (!de_next->down) goto endm;
 		ndown = de_down_pointer(de_next);
-		if (!(de_cp = kmalloc(de->length, GFP_KERNEL))) {
+		if (!(de_cp = kmalloc(de->length, GFP_NOFS))) {
 			printk("HPFS: out of memory for dtree balancing\n");
 			goto endm;
 		}
@@ -650,7 +649,7 @@
 			} else if (down)
 				*(dnode_secno *) ((void *) del + del->length - 4) = down;
 		} else goto endm;
-		if (!(de_cp = kmalloc(de_prev->length, GFP_KERNEL))) {
+		if (!(de_cp = kmalloc(de_prev->length, GFP_NOFS))) {
 			printk("HPFS: out of memory for dtree balancing\n");
 			hpfs_brelse4(&qbh1);
 			goto endm;
@@ -994,7 +993,7 @@
 	int c1, c2 = 0;
 	int d1, d2 = 0;
 	name1 = f->name;
-	if (!(name2 = kmalloc(256, GFP_KERNEL))) {
+	if (!(name2 = kmalloc(256, GFP_NOFS))) {
 		printk("HPFS: out of memory, can't map dirent\n");
 		return NULL;
 	}
diff -Nru a/fs/hpfs/ea.c b/fs/hpfs/ea.c
--- a/fs/hpfs/ea.c	Sat Apr  3 19:38:41 2004
+++ b/fs/hpfs/ea.c	Sat Apr  3 19:38:41 2004
@@ -6,8 +6,6 @@
  *  handling extended attributes
  */
 
-#include <linux/buffer_head.h>
-#include <linux/string.h>
 #include "hpfs_fn.h"
 
 /* Remove external extended attributes. ano specifies whether a is a 
@@ -52,7 +50,7 @@
 static char *get_indirect_ea(struct super_block *s, int ano, secno a, int size)
 {
 	char *ret;
-	if (!(ret = kmalloc(size + 1, GFP_KERNEL))) {
+	if (!(ret = kmalloc(size + 1, GFP_NOFS))) {
 		printk("HPFS: out of memory for EA\n");
 		return NULL;
 	}
@@ -140,7 +138,7 @@
 		if (!strcmp(ea->name, key)) {
 			if (ea->indirect)
 				return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea));
-			if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_KERNEL))) {
+			if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) {
 				printk("HPFS: out of memory for EA\n");
 				return NULL;
 			}
@@ -166,7 +164,7 @@
 		if (!strcmp(ea->name, key)) {
 			if (ea->indirect)
 				return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea));
-			if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_KERNEL))) {
+			if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) {
 				printk("HPFS: out of memory for EA\n");
 				return NULL;
 			}
diff -Nru a/fs/hpfs/file.c b/fs/hpfs/file.c
--- a/fs/hpfs/file.c	Sat Apr  3 19:38:56 2004
+++ b/fs/hpfs/file.c	Sat Apr  3 19:38:56 2004
@@ -6,27 +6,11 @@
  *  file VFS functions
  */
 
-#include <linux/buffer_head.h>
-#include <linux/string.h>
-#include <linux/time.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
 #include "hpfs_fn.h"
 
 #define BLOCKS(size) (((size) + 511) >> 9)
 
-/* HUH? */
-int hpfs_open(struct inode *i, struct file *f)
-{
-	lock_kernel();
-	hpfs_lock_inode(i);
-	hpfs_unlock_inode(i); /* make sure nobody is deleting the file */
-	unlock_kernel();
-	if (!i->i_nlink) return -ENOENT;
-	return 0;
-}
-
-int hpfs_file_release(struct inode *inode, struct file *file)
+static int hpfs_file_release(struct inode *inode, struct file *file)
 {
 	lock_kernel();
 	hpfs_write_if_changed(inode);
@@ -45,7 +29,7 @@
  * so we must ignore such errors.
  */
 
-secno hpfs_bmap(struct inode *inode, unsigned file_secno)
+static secno hpfs_bmap(struct inode *inode, unsigned file_secno)
 {
 	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
 	unsigned n, disk_secno;
@@ -61,7 +45,7 @@
 	return disk_secno;
 }
 
-void hpfs_truncate(struct inode *i)
+static void hpfs_truncate(struct inode *i)
 {
 	if (IS_IMMUTABLE(i)) return /*-EPERM*/;
 	lock_kernel();
@@ -74,7 +58,7 @@
 	unlock_kernel();
 }
 
-int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
+static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
 {
 	secno s;
 	s = hpfs_bmap(inode, iblock);
@@ -124,7 +108,7 @@
 	.bmap = _hpfs_bmap
 };
 
-ssize_t hpfs_file_write(struct file *file, const char __user *buf,
+static ssize_t hpfs_file_write(struct file *file, const char __user *buf,
 			size_t count, loff_t *ppos)
 {
 	ssize_t retval;
@@ -138,3 +122,19 @@
 	return retval;
 }
 
+struct file_operations hpfs_file_ops =
+{
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= hpfs_file_write,
+	.mmap		= generic_file_mmap,
+	.release	= hpfs_file_release,
+	.fsync		= hpfs_file_fsync,
+	.sendfile	= generic_file_sendfile,
+};
+
+struct inode_operations hpfs_file_iops =
+{
+	.truncate	= hpfs_truncate,
+	.setattr	= hpfs_notify_change,
+};
diff -Nru a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h
--- a/fs/hpfs/hpfs_fn.h	Sat Apr  3 19:38:44 2004
+++ b/fs/hpfs/hpfs_fn.h	Sat Apr  3 19:38:44 2004
@@ -9,28 +9,14 @@
 //#define DBG
 //#define DEBUG_LOCKS
 
+#include <linux/pagemap.h>
 #include <linux/buffer_head.h>
-#include <linux/fs.h>
 #include <linux/hpfs_fs.h>
-#include <linux/hpfs_fs_i.h>
-#include <linux/hpfs_fs_sb.h>
-#include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <linux/stat.h>
-#include <linux/string.h>
-#include <asm/bitops.h>
-#include <asm/uaccess.h>
 #include <linux/smp_lock.h>
 
-#include <stdarg.h>
-
 #include "hpfs.h"
 
-#define memcpy_tofs memcpy
-#define memcpy_fromfs memcpy
-
 #define EIOERROR  EIO
 #define EFSERROR  EPERM
 #define EMEMERROR ENOMEM
@@ -56,7 +42,56 @@
 #define PRINTK(x)
 #endif
 
-typedef void nonconst; /* What this is for ? */
+struct hpfs_inode_info {
+	loff_t mmu_private;
+	ino_t i_parent_dir;	/* (directories) gives fnode of parent dir */
+	unsigned i_dno;		/* (directories) root dnode */
+	unsigned i_dpos;	/* (directories) temp for readdir */
+	unsigned i_dsubdno;	/* (directories) temp for readdir */
+	unsigned i_file_sec;	/* (files) minimalist cache of alloc info */
+	unsigned i_disk_sec;	/* (files) minimalist cache of alloc info */
+	unsigned i_n_secs;	/* (files) minimalist cache of alloc info */
+	unsigned i_ea_size;	/* size of extended attributes */
+	unsigned i_conv : 2;	/* (files) crlf->newline hackery */
+	unsigned i_ea_mode : 1;	/* file's permission is stored in ea */
+	unsigned i_ea_uid : 1;	/* file's uid is stored in ea */
+	unsigned i_ea_gid : 1;	/* file's gid is stored in ea */
+	unsigned i_dirty : 1;
+	struct semaphore i_sem;
+	struct semaphore i_parent;
+	loff_t **i_rddir_off;
+	struct inode vfs_inode;
+};
+
+struct hpfs_sb_info {
+	ino_t sb_root;			/* inode number of root dir */
+	unsigned sb_fs_size;		/* file system size, sectors */
+	unsigned sb_bitmaps;		/* sector number of bitmap list */
+	unsigned sb_dirband_start;	/* directory band start sector */
+	unsigned sb_dirband_size;	/* directory band size, dnodes */
+	unsigned sb_dmap;		/* sector number of dnode bit map */
+	unsigned sb_n_free;		/* free blocks for statfs, or -1 */
+	unsigned sb_n_free_dnodes;	/* free dnodes for statfs, or -1 */
+	uid_t sb_uid;			/* uid from mount options */
+	gid_t sb_gid;			/* gid from mount options */
+	umode_t sb_mode;		/* mode from mount options */
+	unsigned sb_conv : 2;		/* crlf->newline hackery */
+	unsigned sb_eas : 2;		/* eas: 0-ignore, 1-ro, 2-rw */
+	unsigned sb_err : 2;		/* on errs: 0-cont, 1-ro, 2-panic */
+	unsigned sb_chk : 2;		/* checks: 0-no, 1-normal, 2-strict */
+	unsigned sb_lowercase : 1;	/* downcase filenames hackery */
+	unsigned sb_was_error : 1;	/* there was an error, set dirty flag */
+	unsigned sb_chkdsk : 2;		/* chkdsk: 0-no, 1-on errs, 2-allways */
+	unsigned char *sb_cp_table;	/* code page tables: */
+					/* 	128 bytes uppercasing table & */
+					/*	128 bytes lowercasing table */
+	unsigned *sb_bmp_dir;		/* main bitmap directory */
+	unsigned sb_c_bitmap;		/* current bitmap */
+	struct semaphore hpfs_creation_de; /* when creating dirents, nobody else
+					   can alloc blocks */
+	/*unsigned sb_mounting : 1;*/
+	int sb_timeshift;
+};
 
 /*
  * conv= options
@@ -162,8 +197,6 @@
 	return 0;
 }
 
-struct statfs;
-
 /* alloc.c */
 
 int hpfs_chk_sectors(struct super_block *, secno, int, char *);
@@ -192,14 +225,6 @@
 
 void hpfs_lock_creation(struct super_block *);
 void hpfs_unlock_creation(struct super_block *);
-void hpfs_lock_iget(struct super_block *, int);
-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);
@@ -213,10 +238,8 @@
 
 /* dir.c */
 
-int hpfs_dir_release(struct inode *, struct file *);
-loff_t hpfs_dir_lseek(struct file *, loff_t, int);
-int hpfs_readdir(struct file *, void *, filldir_t);
 struct dentry *hpfs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct file_operations hpfs_dir_ops;
 
 /* dnode.c */
 
@@ -243,16 +266,14 @@
 
 /* file.c */
 
-int hpfs_file_release(struct inode *, struct file *);
-int hpfs_open(struct inode *, struct file *);
 int hpfs_file_fsync(struct file *, struct dentry *, int);
-secno hpfs_bmap(struct inode *, unsigned);
-void hpfs_truncate(struct inode *);
-int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create);
-ssize_t hpfs_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
+extern struct file_operations hpfs_file_ops;
+extern struct inode_operations hpfs_file_iops;
+extern struct address_space_operations hpfs_aops;
 
 /* inode.c */
 
+void hpfs_init_inode(struct inode *);
 void hpfs_read_inode(struct inode *);
 void hpfs_write_inode_ea(struct inode *, struct fnode *);
 void hpfs_write_inode(struct inode *);
@@ -284,14 +305,8 @@
 
 /* namei.c */
 
-int hpfs_mkdir(struct inode *, struct dentry *, int);
-int hpfs_create(struct inode *, struct dentry *, int, struct nameidata *);
-int hpfs_mknod(struct inode *, struct dentry *, int, dev_t);
-int hpfs_symlink(struct inode *, struct dentry *, const char *);
-int hpfs_unlink(struct inode *, struct dentry *);
-int hpfs_rmdir(struct inode *, struct dentry *);
-int hpfs_symlink_readpage(struct file *, struct page *);
-int hpfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern struct inode_operations hpfs_dir_iops;
+extern struct address_space_operations hpfs_symlink_aops;
 
 static inline struct hpfs_inode_info *hpfs_i(struct inode *inode)
 {
@@ -307,12 +322,7 @@
 
 void hpfs_error(struct super_block *, char *, ...);
 int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *);
-int hpfs_remount_fs(struct super_block *, int *, char *);
-void hpfs_put_super(struct super_block *);
 unsigned hpfs_count_one_bitmap(struct super_block *, secno);
-int hpfs_statfs(struct super_block *, struct kstatfs *);
-
-extern struct address_space_operations hpfs_aops;
 
 /*
  * local time (HPFS) to GMT (Unix)
@@ -329,4 +339,3 @@
 	extern struct timezone sys_tz;
 	return t - sys_tz.tz_minuteswest * 60 - hpfs_sb(s)->sb_timeshift;
 }
-
diff -Nru a/fs/hpfs/inode.c b/fs/hpfs/inode.c
--- a/fs/hpfs/inode.c	Sat Apr  3 19:38:42 2004
+++ b/fs/hpfs/inode.c	Sat Apr  3 19:38:42 2004
@@ -6,65 +6,12 @@
  *  inode VFS functions
  */
 
-#include <linux/fs.h>
-#include <linux/time.h>
-#include <linux/smp_lock.h>
-#include <linux/buffer_head.h>
 #include "hpfs_fn.h"
 
-static struct file_operations hpfs_file_ops =
+void hpfs_init_inode(struct inode *i)
 {
-	.llseek		= generic_file_llseek,
-	.read		= generic_file_read,
-	.write		= hpfs_file_write,
-	.mmap		= generic_file_mmap,
-	.open		= hpfs_open,
-	.release	= hpfs_file_release,
-	.fsync		= hpfs_file_fsync,
-	.sendfile	= generic_file_sendfile,
-};
-
-static struct inode_operations hpfs_file_iops =
-{
-	.truncate	= hpfs_truncate,
-	.setattr	= hpfs_notify_change,
-};
-
-static struct file_operations hpfs_dir_ops =
-{
-	.llseek		= hpfs_dir_lseek,
-	.read		= generic_read_dir,
-	.readdir	= hpfs_readdir,
-	.open		= hpfs_open,
-	.release	= hpfs_dir_release,
-	.fsync		= hpfs_file_fsync,
-};
-
-static struct inode_operations hpfs_dir_iops =
-{
-	.create		= hpfs_create,
-	.lookup		= hpfs_lookup,
-	.unlink		= hpfs_unlink,
-	.symlink	= hpfs_symlink,
-	.mkdir		= hpfs_mkdir,
-	.rmdir		= hpfs_rmdir,
-	.mknod		= hpfs_mknod,
-	.rename		= hpfs_rename,
-	.setattr	= hpfs_notify_change,
-};
-
-struct address_space_operations hpfs_symlink_aops = {
-	.readpage	= hpfs_symlink_readpage
-};
-
-void hpfs_read_inode(struct inode *i)
-{
-	struct buffer_head *bh;
-	struct fnode *fnode;
 	struct super_block *sb = i->i_sb;
 	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
-	unsigned char *ea;
-	int ea_size;
 
 	i->i_uid = hpfs_sb(sb)->sb_uid;
 	i->i_gid = hpfs_sb(sb)->sb_gid;
@@ -91,17 +38,17 @@
 	i->i_ctime.tv_sec = i->i_ctime.tv_nsec = 0;
 	i->i_mtime.tv_sec = i->i_mtime.tv_nsec = 0;
 	i->i_atime.tv_sec = i->i_atime.tv_nsec = 0;
+}
+
+void hpfs_read_inode(struct inode *i)
+{
+	struct buffer_head *bh;
+	struct fnode *fnode;
+	struct super_block *sb = i->i_sb;
+	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
+	unsigned char *ea;
+	int ea_size;
 
-	if (!hpfs_sb(i->i_sb)->sb_rd_inode)
-		hpfs_error(i->i_sb, "read_inode: sb_rd_inode == 0");
-	if (hpfs_sb(i->i_sb)->sb_rd_inode == 2) {
-		i->i_mode |= S_IFREG;
-		i->i_mode &= ~0111;
-		i->i_op = &hpfs_file_iops;
-		i->i_fop = &hpfs_file_ops;
-		i->i_nlink = 1;
-		return;
-	}
 	if (!(fnode = hpfs_map_fnode(sb, i->i_ino, &bh))) {
 		/*i->i_mode |= S_IFREG;
 		i->i_mode &= ~0111;
@@ -233,21 +180,33 @@
 {
 	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
 	struct inode *parent;
-	if (!i->i_nlink) return;
 	if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return;
 	if (hpfs_inode->i_rddir_off && !atomic_read(&i->i_count)) {
 		if (*hpfs_inode->i_rddir_off) printk("HPFS: write_inode: some position still there\n");
 		kfree(hpfs_inode->i_rddir_off);
 		hpfs_inode->i_rddir_off = NULL;
 	}
-	hpfs_inode->i_dirty = 0;
-	hpfs_lock_iget(i->i_sb, 1);
-	parent = iget(i->i_sb, hpfs_inode->i_parent_dir);
-	hpfs_unlock_iget(i->i_sb);
-	hpfs_lock_inode(parent);
-	hpfs_write_inode_nolock(i);
-	hpfs_unlock_inode(parent);
-	iput(parent);
+	down(&hpfs_inode->i_parent);
+	if (!i->i_nlink) {
+		up(&hpfs_inode->i_parent);
+		return;
+	}
+	parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir);
+	if (parent) {
+		hpfs_inode->i_dirty = 0;
+		if (parent->i_state & I_NEW) {
+			hpfs_init_inode(parent);
+			hpfs_read_inode(parent);
+			unlock_new_inode(parent);
+		}
+		down(&hpfs_inode->i_sem);
+		hpfs_write_inode_nolock(i);
+		up(&hpfs_inode->i_sem);
+		iput(parent);
+	} else {
+		mark_inode_dirty(i);
+	}
+	up(&hpfs_inode->i_parent);
 }
 
 void hpfs_write_inode_nolock(struct inode *i)
diff -Nru a/fs/hpfs/map.c b/fs/hpfs/map.c
--- a/fs/hpfs/map.c	Sat Apr  3 19:38:42 2004
+++ b/fs/hpfs/map.c	Sat Apr  3 19:38:42 2004
@@ -6,7 +6,6 @@
  *  mapping structures to memory with some minimal checks
  */
 
-#include <linux/buffer_head.h>
 #include "hpfs_fn.h"
 
 unsigned *hpfs_map_dnode_bitmap(struct super_block *s, struct quad_buffer_head *qbh)
diff -Nru a/fs/hpfs/name.c b/fs/hpfs/name.c
--- a/fs/hpfs/name.c	Sat Apr  3 19:38:55 2004
+++ b/fs/hpfs/name.c	Sat Apr  3 19:38:55 2004
@@ -6,7 +6,6 @@
  *  operations with filenames
  */
 
-#include <linux/string.h>
 #include "hpfs_fn.h"
 
 char *text_postfix[]={
diff -Nru a/fs/hpfs/namei.c b/fs/hpfs/namei.c
--- a/fs/hpfs/namei.c	Sat Apr  3 19:38:43 2004
+++ b/fs/hpfs/namei.c	Sat Apr  3 19:38:43 2004
@@ -6,12 +6,9 @@
  *  adding & removing files & directories
  */
 
-#include <linux/pagemap.h>
-#include <linux/string.h>
-#include <linux/buffer_head.h>
 #include "hpfs_fn.h"
 
-int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
 	const char *name = dentry->d_name.name;
 	unsigned len = dentry->d_name.len;
@@ -28,8 +25,13 @@
 	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;
@@ -37,17 +39,34 @@
 	dee.hidden = name[0] == '.';
 	dee.fnode = fno;
 	dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
-	hpfs_lock_inode(dir);
+	result = new_inode(dir->i_sb);
+	if (!result)
+		goto bail2;
+	hpfs_init_inode(result);
+	result->i_ino = fno;
+	hpfs_i(result)->i_parent_dir = dir->i_ino;
+	hpfs_i(result)->i_dno = dno;
+	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
+	result->i_ctime.tv_nsec = 0; 
+	result->i_mtime.tv_nsec = 0; 
+	result->i_atime.tv_nsec = 0; 
+	hpfs_i(result)->i_ea_size = 0;
+	result->i_mode |= S_IFDIR;
+	result->i_op = &hpfs_dir_iops;
+	result->i_fop = &hpfs_dir_ops;
+	result->i_blocks = 4;
+	result->i_size = 2048;
+	result->i_nlink = 2;
+	if (dee.read_only)
+		result->i_mode &= ~0222;
+
+	down(&hpfs_i(dir)->i_sem);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
-	if (r == 1) goto bail2;
+	if (r == 1)
+		goto bail3;
 	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 bail3;
 	}
 	fnode->len = len;
 	memcpy(fnode->name, name, len > 15 ? 15 : len);
@@ -71,42 +90,35 @@
 	hpfs_mark_4buffers_dirty(&qbh0);
 	hpfs_brelse4(&qbh0);
 	dir->i_nlink++;
-	hpfs_lock_iget(dir->i_sb, 1);
-	if ((result = iget(dir->i_sb, fno))) {
-		hpfs_i(result)->i_parent_dir = dir->i_ino;
-		result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
-		result->i_ctime.tv_nsec = 0; 
-		result->i_mtime.tv_nsec = 0; 
-		result->i_atime.tv_nsec = 0; 
-		hpfs_i(result)->i_ea_size = 0;
-		if (dee.read_only) result->i_mode &= ~0222;
-		if (result->i_uid != current->fsuid ||
-		    result->i_gid != current->fsgid ||
-		    result->i_mode != (mode | S_IFDIR)) {
-			result->i_uid = current->fsuid;
-			result->i_gid = current->fsgid;
-			result->i_mode = mode | S_IFDIR;
-			hpfs_write_inode_nolock(result);
-		}
-		d_instantiate(dentry, result);
+	insert_inode_hash(result);
+
+	if (result->i_uid != current->fsuid ||
+	    result->i_gid != current->fsgid ||
+	    result->i_mode != (mode | S_IFDIR)) {
+		result->i_uid = current->fsuid;
+		result->i_gid = current->fsgid;
+		result->i_mode = mode | S_IFDIR;
+		hpfs_write_inode_nolock(result);
 	}
-	hpfs_unlock_iget(dir->i_sb);
-	hpfs_unlock_inode(dir);
+	d_instantiate(dentry, result);
+	up(&hpfs_i(dir)->i_sem);
 	unlock_kernel();
 	return 0;
+bail3:
+	up(&hpfs_i(dir)->i_sem);
+	iput(result);
 bail2:
 	hpfs_brelse4(&qbh0);
 	hpfs_free_dnode(dir->i_sb, dno);
-	hpfs_unlock_inode(dir);
 bail1:
 	brelse(bh);
 	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)
+static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
 {
 	const char *name = dentry->d_name.name;
 	unsigned len = dentry->d_name.len;
@@ -120,68 +132,83 @@
 	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;
 	dee.hidden = name[0] == '.';
 	dee.fnode = fno;
 	dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
-	hpfs_lock_inode(dir);
+
+	result = new_inode(dir->i_sb);
+	if (!result)
+		goto bail1;
+	
+	hpfs_init_inode(result);
+	result->i_ino = fno;
+	result->i_mode |= S_IFREG;
+	result->i_mode &= ~0111;
+	result->i_op = &hpfs_file_iops;
+	result->i_fop = &hpfs_file_ops;
+	result->i_nlink = 1;
+	hpfs_decide_conv(result, (char *)name, len);
+	hpfs_i(result)->i_parent_dir = dir->i_ino;
+	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
+	result->i_ctime.tv_nsec = 0;
+	result->i_mtime.tv_nsec = 0;
+	result->i_atime.tv_nsec = 0;
+	hpfs_i(result)->i_ea_size = 0;
+	if (dee.read_only)
+		result->i_mode &= ~0222;
+	result->i_blocks = 1;
+	result->i_size = 0;
+	result->i_data.a_ops = &hpfs_aops;
+	hpfs_i(result)->mmu_private = 0;
+
+	down(&hpfs_i(dir)->i_sem);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
-	if (r == 1) goto bail1;
+	if (r == 1)
+		goto bail2;
 	if (r == -1) {
-		brelse(bh);
-		hpfs_free_sectors(dir->i_sb, fno, 1);
-		hpfs_unlock_inode(dir);
-		unlock_kernel();
-		return -EEXIST;
+		err = -EEXIST;
+		goto bail2;
 	}
 	fnode->len = len;
 	memcpy(fnode->name, name, len > 15 ? 15 : len);
 	fnode->up = dir->i_ino;
 	mark_buffer_dirty(bh);
 	brelse(bh);
-	hpfs_lock_iget(dir->i_sb, 2);
-	if ((result = iget(dir->i_sb, fno))) {
-		hpfs_decide_conv(result, (char *)name, len);
-		hpfs_i(result)->i_parent_dir = dir->i_ino;
-		result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
-		result->i_ctime.tv_nsec = 0;
-		result->i_mtime.tv_nsec = 0;
-		result->i_atime.tv_nsec = 0;
-		hpfs_i(result)->i_ea_size = 0;
-		if (dee.read_only) result->i_mode &= ~0222;
-		if (result->i_blocks == -1) result->i_blocks = 1;
-		if (result->i_size == -1) {
-			result->i_size = 0;
-			result->i_data.a_ops = &hpfs_aops;
-			hpfs_i(result)->mmu_private = 0;
-		}
-		if (result->i_uid != current->fsuid ||
-		    result->i_gid != current->fsgid ||
-		    result->i_mode != (mode | S_IFREG)) {
-			result->i_uid = current->fsuid;
-			result->i_gid = current->fsgid;
-			result->i_mode = mode | S_IFREG;
-			hpfs_write_inode_nolock(result);
-		}
-		d_instantiate(dentry, result);
+
+	insert_inode_hash(result);
+
+	if (result->i_uid != current->fsuid ||
+	    result->i_gid != current->fsgid ||
+	    result->i_mode != (mode | S_IFREG)) {
+		result->i_uid = current->fsuid;
+		result->i_gid = current->fsgid;
+		result->i_mode = mode | S_IFREG;
+		hpfs_write_inode_nolock(result);
 	}
-	hpfs_unlock_iget(dir->i_sb);
-	hpfs_unlock_inode(dir);
+	d_instantiate(dentry, result);
+	up(&hpfs_i(dir)->i_sem);
 	unlock_kernel();
 	return 0;
+
+bail2:
+	up(&hpfs_i(dir)->i_sem);
+	iput(result);
 bail1:
 	brelse(bh);
 	hpfs_free_sectors(dir->i_sb, fno, 1);
-	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)
+static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
 {
 	const char *name = dentry->d_name.name;
 	unsigned len = dentry->d_name.len;
@@ -197,63 +224,69 @@
 	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;
 	dee.hidden = name[0] == '.';
 	dee.fnode = fno;
 	dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
-	hpfs_lock_inode(dir);
+
+	result = new_inode(dir->i_sb);
+	if (!result)
+		goto bail1;
+
+	hpfs_init_inode(result);
+	result->i_ino = fno;
+	hpfs_i(result)->i_parent_dir = dir->i_ino;
+	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
+	result->i_ctime.tv_nsec = 0;
+	result->i_mtime.tv_nsec = 0;
+	result->i_atime.tv_nsec = 0;
+	hpfs_i(result)->i_ea_size = 0;
+	result->i_uid = current->fsuid;
+	result->i_gid = current->fsgid;
+	result->i_nlink = 1;
+	result->i_size = 0;
+	result->i_blocks = 1;
+	init_special_inode(result, mode, rdev);
+
+	down(&hpfs_i(dir)->i_sem);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
-	if (r == 1) goto bail1;
+	if (r == 1)
+		goto bail2;
 	if (r == -1) {
-		brelse(bh);
-		hpfs_free_sectors(dir->i_sb, fno, 1);
-		hpfs_unlock_inode(dir);
-		unlock_kernel();
-		return -EEXIST;
+		err = -EEXIST;
+		goto bail2;
 	}
 	fnode->len = len;
 	memcpy(fnode->name, name, len > 15 ? 15 : len);
 	fnode->up = dir->i_ino;
 	mark_buffer_dirty(bh);
-	hpfs_lock_iget(dir->i_sb, 2);
-	if ((result = iget(dir->i_sb, fno))) {
-		hpfs_i(result)->i_parent_dir = dir->i_ino;
-		result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
-		result->i_ctime.tv_nsec = 0;
-		result->i_mtime.tv_nsec = 0;
-		result->i_atime.tv_nsec = 0;
-		hpfs_i(result)->i_ea_size = 0;
-		/*if (result->i_blocks == -1) result->i_blocks = 1;
-		if (result->i_size == -1) result->i_size = 0;*/
-		result->i_uid = current->fsuid;
-		result->i_gid = current->fsgid;
-		result->i_nlink = 1;
-		result->i_size = 0;
-		result->i_blocks = 1;
-		init_special_inode(result, mode, rdev);
-		hpfs_write_inode_nolock(result);
-		d_instantiate(dentry, result);
-	}
-	hpfs_unlock_iget(dir->i_sb);
-	hpfs_unlock_inode(dir);
+
+	insert_inode_hash(result);
+
+	hpfs_write_inode_nolock(result);
+	d_instantiate(dentry, result);
+	up(&hpfs_i(dir)->i_sem);
 	brelse(bh);
 	unlock_kernel();
 	return 0;
+bail2:
+	up(&hpfs_i(dir)->i_sem);
+	iput(result);
 bail1:
 	brelse(bh);
 	hpfs_free_sectors(dir->i_sb, fno, 1);
-	hpfs_unlock_inode(dir);
 bail:
 	unlock_kernel();
-	return -ENOSPC;
+	return err;
 }
 
-extern struct address_space_operations hpfs_symlink_aops;
-
-int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
+static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
 {
 	const char *name = dentry->d_name.name;
 	unsigned len = dentry->d_name.len;
@@ -270,66 +303,70 @@
 		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] == '.';
 	dee.fnode = fno;
 	dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds());
-	hpfs_lock_inode(dir);
+
+	result = new_inode(dir->i_sb);
+	if (!result)
+		goto bail1;
+	result->i_ino = fno;
+	hpfs_init_inode(result);
+	hpfs_i(result)->i_parent_dir = dir->i_ino;
+	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
+	result->i_ctime.tv_nsec = 0;
+	result->i_mtime.tv_nsec = 0;
+	result->i_atime.tv_nsec = 0;
+	hpfs_i(result)->i_ea_size = 0;
+	result->i_mode = S_IFLNK | 0777;
+	result->i_uid = current->fsuid;
+	result->i_gid = current->fsgid;
+	result->i_blocks = 1;
+	result->i_nlink = 1;
+	result->i_size = strlen(symlink);
+	result->i_op = &page_symlink_inode_operations;
+	result->i_data.a_ops = &hpfs_symlink_aops;
+
+	down(&hpfs_i(dir)->i_sem);
 	r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0);
-	if (r == 1) goto bail1;
+	if (r == 1)
+		goto bail2;
 	if (r == -1) {
-		brelse(bh);
-		hpfs_free_sectors(dir->i_sb, fno, 1);
-		hpfs_unlock_inode(dir);
-		unlock_kernel();
-		return -EEXIST;
+		err = -EEXIST;
+		goto bail2;
 	}
 	fnode->len = len;
 	memcpy(fnode->name, name, len > 15 ? 15 : len);
 	fnode->up = dir->i_ino;
+	hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink));
 	mark_buffer_dirty(bh);
 	brelse(bh);
-	hpfs_lock_iget(dir->i_sb, 2);
-	if ((result = iget(dir->i_sb, fno))) {
-		hpfs_i(result)->i_parent_dir = dir->i_ino;
-		result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
-		result->i_ctime.tv_nsec = 0;
-		result->i_mtime.tv_nsec = 0;
-		result->i_atime.tv_nsec = 0;
-		hpfs_i(result)->i_ea_size = 0;
-		/*if (result->i_blocks == -1) result->i_blocks = 1;
-		if (result->i_size == -1) result->i_size = 0;*/
-		result->i_mode = S_IFLNK | 0777;
-		result->i_uid = current->fsuid;
-		result->i_gid = current->fsgid;
-		result->i_blocks = 1;
-		result->i_size = strlen(symlink);
-		result->i_op = &page_symlink_inode_operations;
-		result->i_data.a_ops = &hpfs_symlink_aops;
-		if ((fnode = hpfs_map_fnode(dir->i_sb, fno, &bh))) {
-			hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink));
-			mark_buffer_dirty(bh);
-			brelse(bh);
-		}
-		hpfs_write_inode_nolock(result);
-		d_instantiate(dentry, result);
-	}
-	hpfs_unlock_iget(dir->i_sb);
-	hpfs_unlock_inode(dir);
+
+	insert_inode_hash(result);
+
+	hpfs_write_inode_nolock(result);
+	d_instantiate(dentry, result);
+	up(&hpfs_i(dir)->i_sem);
 	unlock_kernel();
 	return 0;
+bail2:
+	up(&hpfs_i(dir)->i_sem);
+	iput(result);
 bail1:
 	brelse(bh);
 	hpfs_free_sectors(dir->i_sb, fno, 1);
-	hpfs_unlock_inode(dir);
 bail:
 	unlock_kernel();
-	return -ENOSPC;
+	return err;
 }
 
-int hpfs_unlink(struct inode *dir, struct dentry *dentry)
+static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
 {
 	const char *name = dentry->d_name.name;
 	unsigned len = dentry->d_name.len;
@@ -340,39 +377,41 @@
 	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;
-	}
+	down(&hpfs_i(inode)->i_parent);
+	down(&hpfs_i(dir)->i_sem);
+	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 = -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;
+
+		up(&hpfs_i(dir)->i_sem);
+		up(&hpfs_i(inode)->i_parent);
 		d_drop(dentry);
 		spin_lock(&dentry->d_lock);
 		if (atomic_read(&dentry->d_count) > 1 ||
@@ -381,25 +420,35 @@
 		    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:
+	up(&hpfs_i(dir)->i_sem);
+	up(&hpfs_i(inode)->i_parent);
 	unlock_kernel();
-	return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
+	return err;
 }
 
-int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	const char *name = dentry->d_name.name;
 	unsigned len = dentry->d_name.len;
@@ -409,47 +458,57 @@
 	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;
-	}
+	down(&hpfs_i(inode)->i_parent);
+	down(&hpfs_i(dir)->i_sem);
+	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:
+	up(&hpfs_i(dir)->i_sem);
+	up(&hpfs_i(inode)->i_parent);
 	unlock_kernel();
-	return r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
+	return err;
 }
 
-int hpfs_symlink_readpage(struct file *file, struct page *page)
+static int hpfs_symlink_readpage(struct file *file, struct page *page)
 {
 	char *link = kmap(page);
 	struct inode *i = page->mapping->host;
@@ -478,8 +537,12 @@
 	unlock_page(page);
 	return err;
 }
+
+struct address_space_operations hpfs_symlink_aops = {
+	.readpage	= hpfs_symlink_readpage
+};
 	
-int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		struct inode *new_dir, struct dentry *new_dentry)
 {
 	char *old_name = (char *)old_dentry->d_name.name;
@@ -501,7 +564,13 @@
 	hpfs_adjust_length((char *)old_name, &old_len);
 
 	lock_kernel();
-	hpfs_lock_3inodes(old_dir, new_dir, i);
+	/* order doesn't matter, due to VFS exclusion */
+	down(&hpfs_i(i)->i_parent);
+	if (new_inode)
+		down(&hpfs_i(new_inode)->i_parent);
+	down(&hpfs_i(old_dir)->i_sem);
+	if (new_dir != old_dir)
+		down(&hpfs_i(new_dir)->i_sem);
 	
 	/* Erm? Moving over the empty non-busy directory is perfectly legal */
 	if (new_inode && S_ISDIR(new_inode->i_mode)) {
@@ -579,8 +648,26 @@
 	}
 	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);
+end1:
+	if (old_dir != new_dir)
+		up(&hpfs_i(new_dir)->i_sem);
+	up(&hpfs_i(old_dir)->i_sem);
+	up(&hpfs_i(i)->i_parent);
+	if (new_inode)
+		up(&hpfs_i(new_inode)->i_parent);
 	unlock_kernel();
 	return err;
 }
+
+struct inode_operations hpfs_dir_iops =
+{
+	.create		= hpfs_create,
+	.lookup		= hpfs_lookup,
+	.unlink		= hpfs_unlink,
+	.symlink	= hpfs_symlink,
+	.mkdir		= hpfs_mkdir,
+	.rmdir		= hpfs_rmdir,
+	.mknod		= hpfs_mknod,
+	.rename		= hpfs_rename,
+	.setattr	= hpfs_notify_change,
+};
diff -Nru a/fs/hpfs/super.c b/fs/hpfs/super.c
--- a/fs/hpfs/super.c	Sat Apr  3 19:38:44 2004
+++ b/fs/hpfs/super.c	Sat Apr  3 19:38:44 2004
@@ -6,13 +6,11 @@
  *  mounting, unmounting, error handling
  */
 
-#include <linux/buffer_head.h>
-#include <linux/string.h>
 #include "hpfs_fn.h"
 #include <linux/module.h>
 #include <linux/parser.h>
 #include <linux/init.h>
-#include <linux/vfs.h>
+#include <linux/statfs.h>
 
 /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */
 
@@ -101,7 +99,7 @@
 	return 0;
 }
 
-void hpfs_put_super(struct super_block *s)
+static void hpfs_put_super(struct super_block *s)
 {
 	struct hpfs_sb_info *sbi = hpfs_sb(s);
 	if (sbi->sb_cp_table) kfree(sbi->sb_cp_table);
@@ -137,7 +135,7 @@
 	return count;
 }
 
-int hpfs_statfs(struct super_block *s, struct kstatfs *buf)
+static int hpfs_statfs(struct super_block *s, struct kstatfs *buf)
 {
 	struct hpfs_sb_info *sbi = hpfs_sb(s);
 	lock_kernel();
@@ -165,7 +163,7 @@
 static struct inode *hpfs_alloc_inode(struct super_block *sb)
 {
 	struct hpfs_inode_info *ei;
-	ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, SLAB_KERNEL);
+	ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, SLAB_NOFS);
 	if (!ei)
 		return NULL;
 	ei->vfs_inode.i_version = 1;
@@ -184,6 +182,7 @@
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
 		init_MUTEX(&ei->i_sem);
+		init_MUTEX(&ei->i_parent);
 		inode_init_once(&ei->vfs_inode);
 	}
 }
@@ -205,19 +204,6 @@
 		printk(KERN_INFO "hpfs_inode_cache: not all structures were freed\n");
 }
 
-/* Super operations */
-
-static struct super_operations hpfs_sops =
-{
-	.alloc_inode	= hpfs_alloc_inode,
-	.destroy_inode	= hpfs_destroy_inode,
-        .read_inode	= hpfs_read_inode,
-	.delete_inode	= hpfs_delete_inode,
-	.put_super	= hpfs_put_super,
-	.statfs		= hpfs_statfs,
-	.remount_fs	= hpfs_remount_fs,
-};
-
 /*
  * A tiny parser for option strings, stolen from dosfs.
  * Stolen again from read-only hpfs.
@@ -397,7 +383,7 @@
 \n");
 }
 
-int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
+static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
 {
 	uid_t uid;
 	gid_t gid;
@@ -441,6 +427,18 @@
 	return 0;
 }
 
+/* Super operations */
+
+static struct super_operations hpfs_sops =
+{
+	.alloc_inode	= hpfs_alloc_inode,
+	.destroy_inode	= hpfs_destroy_inode,
+	.delete_inode	= hpfs_delete_inode,
+	.put_super	= hpfs_put_super,
+	.statfs		= hpfs_statfs,
+	.remount_fs	= hpfs_remount_fs,
+};
+
 static int hpfs_fill_super(struct super_block *s, void *options, int silent)
 {
 	struct buffer_head *bh0, *bh1, *bh2;
@@ -470,9 +468,7 @@
 	sbi->sb_bmp_dir = NULL;
 	sbi->sb_cp_table = NULL;
 
-	sbi->sb_rd_inode = 0;
 	init_MUTEX(&sbi->hpfs_creation_de);
-	init_waitqueue_head(&sbi->sb_iget_q);
 
 	uid = current->uid;
 	gid = current->gid;
@@ -613,9 +609,12 @@
 	brelse(bh1);
 	brelse(bh0);
 
-	hpfs_lock_iget(s, 1);
-	root = iget(s, sbi->sb_root);
-	hpfs_unlock_iget(s);
+	root = iget_locked(s, sbi->sb_root);
+	if (!root)
+		goto bail0;
+	hpfs_init_inode(root);
+	hpfs_read_inode(root);
+	unlock_new_inode(root);
 	s->s_root = d_alloc_root(root);
 	if (!s->s_root) {
 		iput(root);
diff -Nru a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
--- a/fs/hugetlbfs/inode.c	Sat Apr  3 19:38:55 2004
+++ b/fs/hugetlbfs/inode.c	Sat Apr  3 19:38:55 2004
@@ -62,7 +62,7 @@
 	vma_len = (loff_t)(vma->vm_end - vma->vm_start);
 
 	down(&inode->i_sem);
-	update_atime(inode);
+	file_accessed(file);
 	vma->vm_flags |= VM_HUGETLB | VM_RESERVED;
 	vma->vm_ops = &hugetlb_vm_ops;
 	ret = hugetlb_prefault(mapping, vma);
@@ -683,11 +683,24 @@
 
 static struct vfsmount *hugetlbfs_vfsmount;
 
-static atomic_t hugetlbfs_counter = ATOMIC_INIT(0);
+/*
+ * Return the next identifier for a shm file
+ */
+static unsigned long hugetlbfs_counter(void)
+{
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+	static unsigned long counter;
+	unsigned long ret;
+
+	spin_lock(&lock);
+	ret = ++counter;
+	spin_unlock(&lock);
+	return ret;
+}
 
 struct file *hugetlb_zero_setup(size_t size)
 {
-	int error, n;
+	int error;
 	struct file *file;
 	struct inode *inode;
 	struct dentry *dentry, *root;
@@ -699,11 +712,9 @@
 
 	if (!is_hugepage_mem_enough(size))
 		return ERR_PTR(-ENOMEM);
-	n = atomic_read(&hugetlbfs_counter);
-	atomic_inc(&hugetlbfs_counter);
 
 	root = hugetlbfs_vfsmount->mnt_root;
-	snprintf(buf, 16, "%d", n);
+	snprintf(buf, 16, "%lu", hugetlbfs_counter());
 	quick_string.name = buf;
 	quick_string.len = strlen(quick_string.name);
 	quick_string.hash = 0;
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Sat Apr  3 19:38:56 2004
+++ b/fs/inode.c	Sat Apr  3 19:38:56 2004
@@ -132,6 +132,7 @@
 		inode->i_cdev = NULL;
 		inode->i_rdev = 0;
 		inode->i_security = NULL;
+		inode->dirtied_when = 0;
 		if (security_inode_alloc(inode)) {
 			if (inode->i_sb->s_op->destroy_inode)
 				inode->i_sb->s_op->destroy_inode(inode);
@@ -144,7 +145,6 @@
  		mapping->host = inode;
 		mapping->flags = 0;
 		mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
-		mapping->dirtied_when = 0;
 		mapping->assoc_mapping = NULL;
 		mapping->backing_dev_info = &default_backing_dev_info;
 		if (sb->s_bdev)
@@ -1178,6 +1178,8 @@
 	struct timespec now;
 	int sync_it = 0;
 
+	if (IS_NOCMTIME(inode))
+		return;
 	if (IS_RDONLY(inode))
 		return;
 
diff -Nru a/fs/intermezzo/dir.c b/fs/intermezzo/dir.c
--- a/fs/intermezzo/dir.c	Sat Apr  3 19:38:42 2004
+++ b/fs/intermezzo/dir.c	Sat Apr  3 19:38:42 2004
@@ -1300,13 +1300,9 @@
                 return rc;
         }
 
-        case TCGETS:
-                EXIT;
-                return -EINVAL;
-
         default:
                 EXIT;
-                return -EINVAL;
+                return -ENOTTY;
                 
         }
         EXIT;
diff -Nru a/fs/intermezzo/file.c b/fs/intermezzo/file.c
--- a/fs/intermezzo/file.c	Sat Apr  3 19:38:45 2004
+++ b/fs/intermezzo/file.c	Sat Apr  3 19:38:45 2004
@@ -82,7 +82,7 @@
                 info.remote_generation = dd->remote_generation;
         } else
                 CERROR("get_fileid failed %d, ino: %Lx, fetching by name\n", rc,
-                       dd->remote_ino);
+                       (unsigned long long) dd->remote_ino);
 
         rc = izo_upc_open(minor, pathlen, path, fset->fset_name, &info);
         PRESTO_FREE(buffer, PAGE_SIZE);
@@ -217,9 +217,9 @@
                 fdata->fd_mode = file->f_dentry->d_inode->i_mode;
                 fdata->fd_uid = file->f_dentry->d_inode->i_uid;
                 fdata->fd_gid = file->f_dentry->d_inode->i_gid;
-                fdata->fd_ngroups = current->ngroups;
-                for (i=0 ; i < current->ngroups ; i++)
-                        fdata->fd_groups[i] = current->groups[i];
+                fdata->fd_ngroups = current->group_info->ngroups;
+                for (i=0 ; i < current->group_info->ngroups ; i++)
+                        fdata->fd_groups[i] = GROUP_AT(current->group_info,i);
                 if (!ISLENTO(minor)) 
                         fdata->fd_info.flags = LENTO_FL_KML; 
                 else { 
@@ -380,7 +380,7 @@
                 << file->f_dentry->d_inode->i_sb->s_blocksize_bits);
 
         error = presto_reserve_space(fset->fset_cache, res_size); 
-        CDEBUG(D_INODE, "Reserved %Ld for %d\n", res_size, size); 
+        CDEBUG(D_INODE, "Reserved %Ld for %Zd\n", res_size, size);
         if ( error ) { 
                 EXIT;
                 return -ENOSPC;
@@ -440,7 +440,7 @@
         fops = filter_c2cffops(cache->cache_filter);
         res = fops->write(file, buf, size, off);
         if ( res != size ) {
-                CDEBUG(D_FILE, "file write returns short write: size %d, res %d\n", size, res); 
+                CDEBUG(D_FILE, "file write returns short write: size %Zd, res %Zd\n", size, res); 
         }
 
         if ( (res > 0) && fdata ) 
diff -Nru a/fs/intermezzo/fileset.c b/fs/intermezzo/fileset.c
--- a/fs/intermezzo/fileset.c	Sat Apr  3 19:38:42 2004
+++ b/fs/intermezzo/fileset.c	Sat Apr  3 19:38:42 2004
@@ -418,7 +418,7 @@
         new.fsgid = 0;
         new.fs = get_fs(); 
         /* XXX where can we get the groups from? */
-        new.ngroups = 0;
+        new.group_info = groups_alloc(0);
 
         push_ctxt(save, &new); 
 }
@@ -647,8 +647,9 @@
         CDEBUG(D_FILE,"de:%p dd:%p\n", dentry, dd);
 
         if (dd->remote_ino != 0) {
-                CERROR("remote_ino already set? %Lx:%Lx\n", dd->remote_ino,
-                       dd->remote_generation);
+                CERROR("remote_ino already set? %Lx:%Lx\n",
+                       (unsigned long long) dd->remote_ino,
+                       (unsigned long long) dd->remote_generation);
                 rc = 0;
                 EXIT;
                 goto out_close;
@@ -656,8 +657,9 @@
 
 
         CDEBUG(D_FILE,"setting %p %p, %s to %Lx:%Lx\n", dentry, dd, 
-               buf, data->ioc_ino,
-               data->ioc_generation);
+               buf,
+               (unsigned long long) data->ioc_ino,
+               (unsigned long long) data->ioc_generation);
         dd->remote_ino = data->ioc_ino;
         dd->remote_generation = data->ioc_generation;
 
diff -Nru a/fs/intermezzo/intermezzo_fs.h b/fs/intermezzo/intermezzo_fs.h
--- a/fs/intermezzo/intermezzo_fs.h	Sat Apr  3 19:38:43 2004
+++ b/fs/intermezzo/intermezzo_fs.h	Sat Apr  3 19:38:43 2004
@@ -152,14 +152,14 @@
         uid_t            fsuid;
         gid_t            fsgid;
         mm_segment_t     fs;
-	int              ngroups;
-	gid_t	         groups[NGROUPS];
+        struct group_info * group_info;
+/*	int              ngroups;
+	gid_t	         groups[NGROUPS];*/
 
 };
 
 static inline void push_ctxt(struct run_ctxt *save, struct run_ctxt *new)
 {
-        int i;
         save->fs = get_fs();
         save->pwd = dget(current->fs->pwd);
         save->pwdmnt = mntget(current->fs->pwdmnt);
@@ -167,9 +167,10 @@
         save->fsuid = current->fsuid;
         save->root = current->fs->root;
         save->rootmnt = current->fs->rootmnt;
-        save->ngroups = current->ngroups;
+        save->group_info = current->group_info;
+/*      save->ngroups = current->ngroups;
         for (i = 0; i< current->ngroups; i++) 
-                save->groups[i] = current->groups[i];
+                save->groups[i] = current->groups[i];*/
 
         set_fs(new->fs);
         lock_kernel();
@@ -179,18 +180,17 @@
         unlock_kernel();
         current->fsuid = new->fsuid;
         current->fsgid = new->fsgid;
-        if (new->ngroups > 0) {
+        /*if (new->ngroups > 0) {
                 current->ngroups = new->ngroups;
                 for (i = 0; i< new->ngroups; i++) 
                         current->groups[i] = new->groups[i];
-        }
+        }*/
+        current->group_info = new->group_info;
         
 }
 
 static inline void pop_ctxt(struct run_ctxt *saved)
 {
-        int i;
-
         set_fs(saved->fs);
         lock_kernel();
         set_fs_pwd(current->fs, saved->pwdmnt, saved->pwd);
@@ -199,10 +199,12 @@
         unlock_kernel();
         current->fsuid = saved->fsuid;
         current->fsgid = saved->fsgid;
+        current->group_info = saved->group_info;
+/*
         current->ngroups = saved->ngroups;
         for (i = 0; i< saved->ngroups; i++) 
                 current->groups[i] = saved->groups[i];
-
+*/
         mntput(saved->pwdmnt);
         dput(saved->pwd);
 }
@@ -392,7 +394,7 @@
         uid_t fd_fsuid;
         gid_t fd_fsgid;
         int fd_ngroups;
-        gid_t fd_groups[NGROUPS_MAX];
+        gid_t fd_groups[NGROUPS_SMALL];
         /* information how to complete the close operation */
         struct lento_vfs_context fd_info;
         struct presto_version fd_version;
diff -Nru a/fs/intermezzo/intermezzo_kml.h b/fs/intermezzo/intermezzo_kml.h
--- a/fs/intermezzo/intermezzo_kml.h	Sat Apr  3 19:38:57 2004
+++ b/fs/intermezzo/intermezzo_kml.h	Sat Apr  3 19:38:57 2004
@@ -41,7 +41,7 @@
         u32 fsgid;
         u32 opcode;
         u32 ngroups;
-        u32 groups[NGROUPS_MAX];
+        u32 groups[NGROUPS_SMALL];
 };
 
 enum kml_opcode {
diff -Nru a/fs/intermezzo/journal.c b/fs/intermezzo/journal.c
--- a/fs/intermezzo/journal.c	Sat Apr  3 19:38:40 2004
+++ b/fs/intermezzo/journal.c	Sat Apr  3 19:38:40 2004
@@ -309,7 +309,7 @@
                                        __u32 fsuid, __u32 fsgid)
 {
         struct kml_prefix_hdr p;
-        u32 loggroups[NGROUPS_MAX];
+        u32 loggroups[NGROUPS_SMALL];
 
         int i; 
 
@@ -332,15 +332,15 @@
 static inline char *
 journal_log_prefix(char *buf, int opcode, struct rec_info *rec)
 {
-        __u32 groups[NGROUPS_MAX]; 
+        __u32 groups[NGROUPS_SMALL]; 
         int i; 
 
         /* convert 16 bit gid's to 32 bit gid's */
-        for (i=0; i<current->ngroups; i++) 
-                groups[i] = (__u32) current->groups[i];
+        for (i=0; i<current->group_info->ngroups; i++) 
+                groups[i] = GROUP_AT(current->group_info,i);
         
         return journal_log_prefix_with_groups_and_ids(buf, opcode, rec,
-                                                      (__u32)current->ngroups,
+                                                      (__u32)current->group_info->ngroups,
                                                       groups,
                                                       (__u32)current->fsuid,
                                                       (__u32)current->fsgid);
@@ -1319,7 +1319,7 @@
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
         ino = cpu_to_le64(dentry->d_inode->i_ino);
         generation = cpu_to_le32(dentry->d_inode->i_generation);
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + sizeof(*new_file_ver) +
                 sizeof(ino) + sizeof(generation) + sizeof(pathlen) +
                 sizeof(remote_ino) + sizeof(remote_generation) + 
@@ -1470,7 +1470,7 @@
                 return 0;
         }
 
-        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %d\n", 
+        CDEBUG(D_JOURNAL, "reading prefix: off %ld, size %Zd\n", 
                (long)lml_offset, sizeof(record));
         rc = presto_fread(fset->fset_lml.fd_file, (char *)&record,
                           sizeof(record), &offset);
@@ -1529,7 +1529,7 @@
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + sizeof(*old_ver) +
                 sizeof(valid) + sizeof(mode) + sizeof(uid) + sizeof(gid) +
                 sizeof(fsize) + sizeof(mtime) + sizeof(ctime) + sizeof(flags) +
@@ -1600,7 +1600,7 @@
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + sizeof(pathlen) +
                 size_round(le32_to_cpu(pathlen)) +
                 sizeof(struct kml_suffix);
@@ -1621,7 +1621,7 @@
         /* journal_log_suffix expects journal_log to set this */
         suffix->recno = 0;
 
-        CDEBUG(D_FILE, "actual kml size: %d\n", logrecord - record);
+        CDEBUG(D_FILE, "actual kml size: %Zd\n", logrecord - record);
         CDEBUG(D_FILE, "get fileid: uid %d, gid %d, path: %s\n", uid, gid,path);
 
         error = izo_upc_get_fileid(minor, size, record, 
@@ -1659,7 +1659,7 @@
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
                 sizeof(struct kml_suffix);
@@ -1715,7 +1715,7 @@
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
                 sizeof(targetlen) + sizeof(struct kml_suffix);
@@ -1773,7 +1773,7 @@
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size = sizeof(__u32) * current->ngroups + 
+        size = sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(pathlen) +
                 sizeof(struct kml_suffix);
@@ -1828,7 +1828,7 @@
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dir, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(pathlen) + sizeof(llen) + sizeof(*rb) +
                 sizeof(struct kml_suffix);
@@ -1891,7 +1891,7 @@
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dentry, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size = sizeof(__u32) * current->ngroups + 
+        size = sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(lmode) + sizeof(uid) + sizeof(gid) + sizeof(lmajor) +
                 sizeof(lminor) + sizeof(pathlen) +
@@ -1951,7 +1951,7 @@
         BUFF_ALLOC(buffer, srcbuffer);
         path = presto_path(tgt, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(srcpathlen) + sizeof(pathlen) +
                 sizeof(struct kml_suffix);
@@ -2009,7 +2009,7 @@
         BUFF_ALLOC(buffer, srcbuffer);
         path = presto_path(tgt, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 4 * sizeof(*src_dir_ver) +
                 sizeof(srcpathlen) + sizeof(pathlen) +
                 sizeof(struct kml_suffix);
@@ -2069,7 +2069,7 @@
         BUFF_ALLOC(buffer, NULL);
         path = presto_path(dir, root, buffer, PAGE_SIZE);
         pathlen = cpu_to_le32(MYPATHLEN(buffer, path));
-        size = sizeof(__u32) * current->ngroups + 
+        size = sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 3 * sizeof(*tgt_dir_ver) +
                 sizeof(pathlen) + sizeof(llen) + sizeof(*rb) +
                 sizeof(old_targetlen) + sizeof(struct kml_suffix);
@@ -2116,7 +2116,7 @@
         __u32 open_fsuid;
         __u32 open_fsgid;
         __u32 open_ngroups;
-        __u32 open_groups[NGROUPS_MAX];
+        __u32 open_groups[NGROUPS_SMALL];
         __u32 open_mode;
         __u32 open_uid;
         __u32 open_gid;
@@ -2146,9 +2146,9 @@
                 open_fsuid = fd->fd_fsuid;
                 open_fsgid = fd->fd_fsgid;
         } else {
-                open_ngroups = current->ngroups;
-                for (i=0; i<current->ngroups; i++)
-                        open_groups[i] =  (__u32) current->groups[i]; 
+                open_ngroups = current->group_info->ngroups;
+                for (i=0; i<current->group_info->ngroups; i++)
+                        open_groups[i] =  (__u32) GROUP_AT(current->group_info,i); 
                 open_mode = dentry->d_inode->i_mode;
                 open_uid = dentry->d_inode->i_uid;
                 open_gid = dentry->d_inode->i_gid;
@@ -2246,7 +2246,7 @@
 /* write closes for the local close records in the LML */ 
 int presto_complete_lml(struct presto_file_set *fset)
 {
-        __u32 groups[NGROUPS_MAX];
+        __u32 groups[NGROUPS_SMALL];
         loff_t lml_offset;
         loff_t read_offset; 
         char *buffer;
@@ -2408,7 +2408,7 @@
          */
         mode=cpu_to_le32(dentry->d_inode->i_mode);
 
-        size =  sizeof(__u32) * current->ngroups + 
+        size =  sizeof(__u32) * current->group_info->ngroups + 
                 sizeof(struct kml_prefix_hdr) + 
                 2 * sizeof(struct presto_version) +
                 sizeof(flags) + sizeof(mode) + sizeof(namelen) + 
diff -Nru a/fs/intermezzo/journal_xfs.c b/fs/intermezzo/journal_xfs.c
--- a/fs/intermezzo/journal_xfs.c	Sat Apr  3 19:38:55 2004
+++ b/fs/intermezzo/journal_xfs.c	Sat Apr  3 19:38:55 2004
@@ -57,7 +57,7 @@
         VFS_STATVFS(vfsp, &stat, NULL, rc);
         avail = statp.f_bfree;
 
-        return sbp->sb_fdblocks;; 
+        return sbp->sb_fdblocks;
 #endif
         return 0x0fffffff;
 }
diff -Nru a/fs/intermezzo/kml_reint.c b/fs/intermezzo/kml_reint.c
--- a/fs/intermezzo/kml_reint.c	Sat Apr  3 19:38:55 2004
+++ b/fs/intermezzo/kml_reint.c	Sat Apr  3 19:38:55 2004
@@ -53,11 +53,11 @@
         ctxt.root = ctxt.pwd;
         ctxt.rootmnt = ctxt.pwdmnt;
         if (rec->prefix.hdr->ngroups > 0) {
-                ctxt.ngroups = rec->prefix.hdr->ngroups;
-                for (i = 0; i< ctxt.ngroups; i++) 
-                        ctxt.groups[i] = rec->prefix.groups[i];
+                ctxt.group_info = groups_alloc(rec->prefix.hdr->ngroups);
+                for (i = 0; i< ctxt.group_info->ngroups; i++) 
+                        GROUP_AT(ctxt.group_info,i)= rec->prefix.groups[i];
         } else
-                ctxt.ngroups = 0;
+                ctxt.group_info = groups_alloc(0);
 
         push_ctxt(saved, &ctxt);
 }
@@ -162,7 +162,8 @@
                          */
                         if (error == ENOENT) {
                                 CDEBUG(D_KML, "manually updating remote offset uuid %s"
-                                       "recno %d offset %Lu\n", info.uuid, info.recno, info.kml_offset);
+                                       "recno %d offset %Lu\n", info.uuid, info.recno,
+                                       (unsigned long long) info.kml_offset);
                                 error = izo_rcvd_upd_remote(fset, info.uuid, info.recno, info.kml_offset);
                                 if(error)
                                         CERROR("izo_rcvd_upd_remote error %d\n", error);
@@ -528,7 +529,7 @@
 
         if (rec.suffix->recno != lr_rec.lr_remote_recno + 1) {
                 CERROR("KML record number %Lu expected, not %d\n",
-                       lr_rec.lr_remote_recno + 1,
+                       (unsigned long long) (lr_rec.lr_remote_recno + 1),
                        rec.suffix->recno);
 
 #if 0
@@ -631,8 +632,9 @@
         data->ioc_generation = file->f_dentry->d_inode->i_generation; 
         filp_close(file, 0); 
 
-        CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path, 
-               data->ioc_ino, data->ioc_generation);
+        CDEBUG(D_FILE, "%s ino %Lx, gen %Lx\n", rec.path,
+               (unsigned long long) data->ioc_ino,
+               (unsigned long long) data->ioc_generation);
 
  out:
         if (buf) 
diff -Nru a/fs/intermezzo/psdev.c b/fs/intermezzo/psdev.c
--- a/fs/intermezzo/psdev.c	Sat Apr  3 19:38:42 2004
+++ b/fs/intermezzo/psdev.c	Sat Apr  3 19:38:42 2004
@@ -227,7 +227,7 @@
 
         /* move data into response buffer. */
         if (req->rq_bufsize < count) {
-                CERROR("psdev_write: too much cnt: %d, cnt: %d, "
+                CERROR("psdev_write: too much cnt: %d, cnt: %Zd, "
                        "opc: %d, uniq: %d.\n",
                        req->rq_bufsize, count, hdr.opcode, hdr.unique);
                 count = req->rq_bufsize; /* don't have more space! */
@@ -281,7 +281,7 @@
         }
 
         if (count < req->rq_bufsize) {
-                CERROR ("psdev_read: buffer too small, read %d of %d bytes\n",
+                CERROR ("psdev_read: buffer too small, read %Zd of %d bytes\n",
                         count, req->rq_bufsize);
         }
 
@@ -592,8 +592,8 @@
                req->rq_opcode, jiffies - req->rq_posttime,
                req->rq_unique, req->rq_rep_size);
         CDEBUG(D_UPCALL,
-               "..process %d woken up by Lento for req at 0x%x, data at %x\n",
-               current->pid, (int)req, (int)req->rq_data);
+               "..process %d woken up by Lento for req at 0x%p, data at %p\n",
+               current->pid, req, req->rq_data);
 
         if (channel->uc_pid) {      /* i.e. Lento is still alive */
           /* Op went through, interrupt or not we go on */
diff -Nru a/fs/intermezzo/upcall.c b/fs/intermezzo/upcall.c
--- a/fs/intermezzo/upcall.c	Sat Apr  3 19:38:56 2004
+++ b/fs/intermezzo/upcall.c	Sat Apr  3 19:38:56 2004
@@ -142,7 +142,10 @@
 
         CDEBUG(D_UPCALL, "KML: fileset %s, offset %Lu, length %Lu, "
                "first %u, last %d; minor %d\n",
-               fsetname, hdr->u_offset, hdr->u_length, hdr->u_first_recno,
+               fsetname,
+               (unsigned long long) hdr->u_offset,
+               (unsigned long long) hdr->u_length,
+               hdr->u_first_recno,
                hdr->u_last_recno, minor);
 
         error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
@@ -174,7 +177,9 @@
 
         CDEBUG(D_UPCALL, "KML TRUNCATE: fileset %s, length %Lu, "
                "last recno %d, minor %d\n",
-               fsetname, hdr->u_length, hdr->u_last_recno, minor);
+               fsetname,
+               (unsigned long long) hdr->u_length,
+               hdr->u_last_recno, minor);
 
         error = izo_upc_upcall(minor, &size, hdr, ASYNCHRONOUS);
 
diff -Nru a/fs/intermezzo/vfs.c b/fs/intermezzo/vfs.c
--- a/fs/intermezzo/vfs.c	Sat Apr  3 19:38:42 2004
+++ b/fs/intermezzo/vfs.c	Sat Apr  3 19:38:42 2004
@@ -965,8 +965,6 @@
                 do_rcvd = presto_do_rcvd(info, dir);
                 error = iops->unlink(dir->d_inode, dentry);
                 unlock_kernel();
-                if (!error)
-                        d_delete(dentry);
         }
 
         if (linkno > 1) { 
@@ -988,10 +986,6 @@
         }
 
         //        up(&dir->d_inode->i_zombie);
-        if (error) {
-                EXIT;
-                goto exit;
-        }
 
         presto_debug_fail_blkdev(fset, KML_OPCODE_UNLINK | 0x10);
         if ( do_kml )
@@ -1048,6 +1042,8 @@
                 if (nd.last.name[nd.last.len])
                         goto slashes;
                 error = presto_do_unlink(fset, nd.dentry, dentry, info);
+                if (!error)
+                        d_delete(dentry);
         exit2:
                 EXIT;
                 dput(dentry);
diff -Nru a/fs/jbd/recovery.c b/fs/jbd/recovery.c
--- a/fs/jbd/recovery.c	Sat Apr  3 19:38:55 2004
+++ b/fs/jbd/recovery.c	Sat Apr  3 19:38:55 2004
@@ -137,7 +137,10 @@
 
 	*bhp = NULL;
 
-	J_ASSERT (offset < journal->j_maxlen);
+	if (offset >= journal->j_maxlen) {
+		printk(KERN_ERR "JBD: corrupted journal superblock\n");
+		return -EIO;
+	}
 
 	err = journal_bmap(journal, offset, &blocknr);
 
diff -Nru a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
--- a/fs/jffs/inode-v23.c	Sat Apr  3 19:38:44 2004
+++ b/fs/jffs/inode-v23.c	Sat Apr  3 19:38:44 2004
@@ -70,6 +70,8 @@
 	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 -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c
--- a/fs/jffs2/super.c	Sat Apr  3 19:38:42 2004
+++ b/fs/jffs2/super.c	Sat Apr  3 19:38:42 2004
@@ -129,6 +129,7 @@
 		  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 -Nru a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
--- a/fs/jfs/jfs_dmap.c	Sat Apr  3 19:38:55 2004
+++ b/fs/jfs/jfs_dmap.c	Sat Apr  3 19:38:55 2004
@@ -1526,6 +1526,7 @@
 			if (n == 4) {
 				jfs_error(bmp->db_ipbmap->i_sb,
 					  "dbAllocAG: failed descending stree");
+				release_metapage(mp);
 				return -EIO;
 			}
 		}
@@ -3310,7 +3311,7 @@
 	int i, i0 = TRUE, j, j0 = TRUE, k, n;
 	s64 newsize;
 	s64 p;
-	struct metapage *mp, *l2mp, *l1mp, *l0mp;
+	struct metapage *mp, *l2mp, *l1mp = NULL, *l0mp = NULL;
 	struct dmapctl *l2dcp, *l1dcp, *l0dcp;
 	struct dmap *dp;
 	s8 *l0leaf, *l1leaf, *l2leaf;
@@ -3513,6 +3514,7 @@
 			 */
 			*l1leaf = dbInitDmapCtl(l0dcp, 0, ++i);
 			write_metapage(l0mp);
+			l0mp = NULL;
 
 			if (nblocks)
 				l1leaf++;	/* continue for next L0 */
@@ -3536,6 +3538,7 @@
 		 */
 		*l2leaf = dbInitDmapCtl(l1dcp, 1, ++j);
 		write_metapage(l1mp);
+		l1mp = NULL;
 
 		if (nblocks)
 			l2leaf++;	/* continue for next L1 */
@@ -3554,17 +3557,20 @@
 
 	jfs_error(ipbmap->i_sb,
 		  "dbExtendFS: function has not returned as expected");
+errout:
+	if (l0mp)
+		release_metapage(l0mp);
+	if (l1mp)
+		release_metapage(l1mp);
+	release_metapage(l2mp);
 	return -EIO;
 
 	/*
 	 *      finalize bmap control page
 	 */
-      finalize:
+finalize:
 
 	return 0;
-
-      errout:
-	return -EIO;
 }
 
 
diff -Nru a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
--- a/fs/jfs/jfs_dtree.c	Sat Apr  3 19:38:54 2004
+++ b/fs/jfs/jfs_dtree.c	Sat Apr  3 19:38:54 2004
@@ -1423,8 +1423,10 @@
 	 */
 	if (nextbn != 0) {
 		DT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
-		if (rc)
+		if (rc) {
+			discard_metapage(rmp);
 			return rc;
+		}
 
 		BT_MARK_DIRTY(mp, ip);
 		/*
@@ -2235,8 +2237,10 @@
 	pxdlock->index = 1;
 
 	/* update sibling pointers */
-	if ((rc = dtRelink(tid, ip, fp)))
+	if ((rc = dtRelink(tid, ip, fp))) {
+		BT_PUTPAGE(fmp);
 		return rc;
+	}
 
 	xlen = lengthPXD(&fp->header.self);
 	ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
@@ -2307,8 +2311,10 @@
 				pxdlock->index = 1;
 
 				/* update sibling pointers */
-				if ((rc = dtRelink(tid, ip, p)))
+				if ((rc = dtRelink(tid, ip, p))) {
+					DT_PUTPAGE(mp);
 					return rc;
+				}
 
 				xlen = lengthPXD(&p->header.self);
 				ip->i_blocks -= LBLK2PBLK(ip->i_sb, xlen);
@@ -2621,8 +2627,10 @@
 		/*
 		 * descend down to leftmost child page
 		 */
-		if (p->header.flag & BT_LEAF)
+		if (p->header.flag & BT_LEAF) {
+			DT_PUTPAGE(mp);
 			return -ESTALE;
+		}
 
 		/* get the leftmost entry */
 		stbl = DT_GETSTBL(p);
diff -Nru a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
--- a/fs/jfs/jfs_imap.c	Sat Apr  3 19:38:41 2004
+++ b/fs/jfs/jfs_imap.c	Sat Apr  3 19:38:41 2004
@@ -1546,6 +1546,7 @@
 						 0);
 				if (rem >= INOSPEREXT) {
 					IREAD_UNLOCK(ipimap);
+					release_metapage(mp);
 					AG_UNLOCK(imap, agno);
 					jfs_error(ip->i_sb,
 						  "diAlloc: can't find free bit "
@@ -1840,6 +1841,7 @@
 	 */
 	if (!iagp->nfreeinos) {
 		IREAD_UNLOCK(imap->im_ipimap);
+		release_metapage(mp);
 		jfs_error(ip->i_sb,
 			  "diAllocIno: nfreeinos = 0, but iag on freelist");
 		return -EIO;
@@ -1851,6 +1853,7 @@
 	for (sword = 0;; sword++) {
 		if (sword >= SMAPSZ) {
 			IREAD_UNLOCK(imap->im_ipimap);
+			release_metapage(mp);
 			jfs_error(ip->i_sb,
 				  "diAllocIno: free inode not found in summary map");
 			return -EIO;
@@ -1866,6 +1869,7 @@
 	rem = diFindFree(le32_to_cpu(iagp->inosmap[sword]), 0);
 	if (rem >= EXTSPERSUM) {
 		IREAD_UNLOCK(imap->im_ipimap);
+		release_metapage(mp);
 		jfs_error(ip->i_sb, "diAllocIno: no free extent found");
 		return -EIO;
 	}
@@ -1876,6 +1880,7 @@
 	rem = diFindFree(le32_to_cpu(iagp->wmap[extno]), 0);
 	if (rem >= INOSPEREXT) {
 		IREAD_UNLOCK(imap->im_ipimap);
+		release_metapage(mp);
 		jfs_error(ip->i_sb, "diAllocIno: free inode not found");
 		return -EIO;
 	}
@@ -2839,12 +2844,14 @@
 		 * and should be free in persistent map;
 		 */
 		if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
+			release_metapage(mp);
 			jfs_error(ipimap->i_sb,
 				  "diUpdatePMap: the inode is not allocated in "
 				  "the working map");
 			return -EIO;
 		}
 		if ((le32_to_cpu(iagp->pmap[extno]) & mask) != 0) {
+			release_metapage(mp);
 			jfs_error(ipimap->i_sb,
 				  "diUpdatePMap: the inode is not free in the "
 				  "persistent map");
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Sat Apr  3 19:38:43 2004
+++ b/fs/jfs/jfs_logmgr.c	Sat Apr  3 19:38:43 2004
@@ -979,7 +979,6 @@
 		 * We need to make sure all of the "written" metapages
 		 * actually make it to disk
 		 */
-		down(&jfs_log_sem);
 		list_for_each_entry(sbi, &log->sb_list, log_list) {
 			filemap_fdatawrite(sbi->ipbmap->i_mapping);
 			filemap_fdatawrite(sbi->ipimap->i_mapping);
@@ -990,7 +989,6 @@
 			filemap_fdatawait(sbi->ipimap->i_mapping);
 			filemap_fdatawait(sbi->sb->s_bdev->bd_inode->i_mapping);
 		}
-		up(&jfs_log_sem);
 
 		lrd.logtid = 0;
 		lrd.backchain = 0;
@@ -1151,8 +1149,10 @@
 		goto shutdown;
 
 journal_found:
+	LOG_LOCK(log);
 	list_add(&sbi->log_list, &log->sb_list);
 	sbi->log = log;
+	LOG_UNLOCK(log);
 
 	up(&jfs_log_sem);
 	return 0;
@@ -1237,8 +1237,10 @@
 		}
 	}
 
+	LOG_LOCK(dummy_log);
 	list_add(&JFS_SBI(sb)->log_list, &dummy_log->sb_list);
 	JFS_SBI(sb)->log = dummy_log;
+	LOG_UNLOCK(dummy_log);
 	up(&jfs_log_sem);
 
 	return 0;
@@ -1369,14 +1371,13 @@
 			 le32_to_cpu(logsuper->end), log->page, log->eor,
 			 le16_to_cpu(lp->h.eor));
 
-		/* if current page is full, move on to next page */
-		if (log->eor >= LOGPSIZE - LOGPTLRSIZE)
-			lmNextPage(log);
-
 		log->bp = bp;
 		bp->l_pn = log->page;
 		bp->l_eor = log->eor;
 
+		/* if current page is full, move on to next page */
+		if (log->eor >= LOGPSIZE - LOGPTLRSIZE)
+			lmNextPage(log);
 
 		/*
 		 * initialize log syncpoint
@@ -1469,7 +1470,9 @@
 	jfs_info("lmLogClose: log:0x%p", log);
 
 	down(&jfs_log_sem);
+	LOG_LOCK(log);
 	list_del(&sbi->log_list);
+	LOG_UNLOCK(log);
 	sbi->log = NULL;
 
 	/*
@@ -1811,7 +1814,7 @@
 		lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
 		if (lbuf == 0)
 			goto error;
-		lbuf->l_ldata = (char *) __get_free_page(GFP_KERNEL);
+		lbuf->l_ldata = (char *) get_zeroed_page(GFP_KERNEL);
 		if (lbuf->l_ldata == 0) {
 			kfree(lbuf);
 			goto error;
diff -Nru a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
--- a/fs/jfs/jfs_metapage.c	Sat Apr  3 19:38:42 2004
+++ b/fs/jfs/jfs_metapage.c	Sat Apr  3 19:38:42 2004
@@ -341,6 +341,10 @@
 		}
 		mp->data = kmap(mp->page) + page_offset;
 	}
+
+	if (new)
+		memset(mp->data, 0, PSIZE);
+
 	jfs_info("__get_metapage: returning = 0x%p", mp);
 	return mp;
 
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Sat Apr  3 19:38:44 2004
+++ b/fs/jfs/jfs_txnmgr.c	Sat Apr  3 19:38:44 2004
@@ -1356,9 +1356,6 @@
 		lrd->log.redopage.fileset = cpu_to_le32(JFS_IP(ip)->fileset);
 		lrd->log.redopage.inode = cpu_to_le32(ip->i_ino);
 
-		if (tlck->mp)
-			hold_metapage(tlck->mp, 0);
-
 		/* write log record of page from the tlock */
 		switch (tlck->type & tlckTYPE) {
 		case tlckXTREE:
@@ -1384,8 +1381,6 @@
 		default:
 			jfs_err("UFO tlock:0x%p", tlck);
 		}
-		if (tlck->mp)
-			release_metapage(tlck->mp);
 	}
 
 	return rc;
@@ -1535,6 +1530,7 @@
 		 * the last entry, so don't bother logging this
 		 */
 		mp->lid = 0;
+		hold_metapage(mp, 0);
 		atomic_dec(&mp->nohomeok);
 		discard_metapage(mp);
 		tlck->mp = 0;
diff -Nru a/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
--- a/fs/jfs/jfs_xtree.c	Sat Apr  3 19:38:43 2004
+++ b/fs/jfs/jfs_xtree.c	Sat Apr  3 19:38:43 2004
@@ -1032,11 +1032,11 @@
 	rc = (sp->header.flag & BT_ROOT) ?
 	    xtSplitRoot(tid, ip, split, &rmp) :
 	    xtSplitPage(tid, ip, split, &rmp, &rbn);
-	if (rc)
-		return -EIO;
 
 	XT_PUTPAGE(smp);
 
+	if (rc)
+		return -EIO;
 	/*
 	 * propagate up the router entry for the leaf page just split
 	 *
@@ -1611,14 +1611,16 @@
 	/* there must exist extent to be extended */
 	if ((rc = xtSearch(ip, xoff - 1, &cmp, &btstack, XT_INSERT)))
 		return rc;
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
 	if (cmp != 0) {
+		XT_PUTPAGE(mp);
 		jfs_error(ip->i_sb, "xtExtend: xtSearch did not find extent");
 		return -EIO;
 	}
 
-	/* retrieve search result */
-	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
-
 	/* extension must be contiguous */
 	xad = &p->xad[index];
 	if ((offsetXAD(xad) + lengthXAD(xad)) != xoff) {
@@ -1677,25 +1679,27 @@
 		 * resides on the new child page;
 		 */
 		if (rootsplit) {
-			if (p->header.nextindex ==
-			    cpu_to_le16(XTENTRYSTART + 1)) {
-				xad = &p->xad[XTENTRYSTART];
-				bn = addressXAD(xad);
-
-				/* get new child page */
-				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
-
-				BT_MARK_DIRTY(mp, ip);
-				if (!test_cflag(COMMIT_Nolink, ip)) {
-					tlck = txLock(tid, ip, mp,
-						      tlckXTREE |
-						      tlckGROW);
-					xtlck = (struct xtlock *) & tlck->lock;
-				}
+			ASSERT(p->header.nextindex ==
+			       cpu_to_le16(XTENTRYSTART + 1));
+			xad = &p->xad[XTENTRYSTART];
+			bn = addressXAD(xad);
+
+			/* get new child page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+
+			BT_MARK_DIRTY(mp, ip);
+			if (!test_cflag(COMMIT_Nolink, ip)) {
+				tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
+				xtlck = (struct xtlock *) & tlck->lock;
 			}
-		} else
+		} else {
 			/* get back old page */
 			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+		}
 	}
 	/*
 	 *      insert the new entry into the leaf page
@@ -1778,14 +1782,16 @@
 	/* there must exist extent to be tailgated */
 	if ((rc = xtSearch(ip, xoff, &cmp, &btstack, XT_INSERT)))
 		return rc;
+
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
 	if (cmp != 0) {
+		XT_PUTPAGE(mp);
 		jfs_error(ip->i_sb, "xtTailgate: couldn't find extent");
 		return -EIO;
 	}
 
-	/* retrieve search result */
-	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
-
 	/* entry found must be last entry */
 	nextindex = le16_to_cpu(p->header.nextindex);
 	if (index != nextindex - 1) {
@@ -1843,25 +1849,27 @@
 		 * resides on the new child page;
 		 */
 		if (rootsplit) {
-			if (p->header.nextindex ==
-			    cpu_to_le16(XTENTRYSTART + 1)) {
-				xad = &p->xad[XTENTRYSTART];
-				bn = addressXAD(xad);
-
-				/* get new child page */
-				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
-
-				BT_MARK_DIRTY(mp, ip);
-				if (!test_cflag(COMMIT_Nolink, ip)) {
-					tlck = txLock(tid, ip, mp,
-						      tlckXTREE |
-						      tlckGROW);
-					xtlck = (struct xtlock *) & tlck->lock;
-				}
+			ASSERT(p->header.nextindex ==
+			       cpu_to_le16(XTENTRYSTART + 1));
+			xad = &p->xad[XTENTRYSTART];
+			bn = addressXAD(xad);
+
+			/* get new child page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+
+			BT_MARK_DIRTY(mp, ip);
+			if (!test_cflag(COMMIT_Nolink, ip)) {
+				tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
+				xtlck = (struct xtlock *) & tlck->lock;
 			}
-		} else
+		} else {
 			/* get back old page */
 			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+		}
 	}
 	/*
 	 *      insert the new entry into the leaf page
@@ -1960,14 +1968,15 @@
 	if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
 		return rc;
 
+	/* retrieve search result */
+	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
+
 	if (cmp != 0) {
+		XT_PUTPAGE(mp);
 		jfs_error(ip->i_sb, "xtUpdate: Could not find extent");
 		return -EIO;
 	}
 
-	/* retrieve search result */
-	XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
-
 	BT_MARK_DIRTY(mp, ip);
 	/*
 	 * acquire tlock of the leaf page containing original entry
@@ -2175,25 +2184,26 @@
 		 * resides on the new child page;
 		 */
 		if (rootsplit) {
-			if (p->header.nextindex ==
-			    cpu_to_le16(XTENTRYSTART + 1)) {
-				xad = &p->xad[XTENTRYSTART];
-				bn = addressXAD(xad);
-
-				/* get new child page */
-				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
-
-				BT_MARK_DIRTY(mp, ip);
-				if (!test_cflag(COMMIT_Nolink, ip)) {
-					tlck = txLock(tid, ip, mp,
-						      tlckXTREE |
-						      tlckGROW);
-					xtlck = (struct xtlock *) & tlck->lock;
-				}
+			ASSERT(p->header.nextindex ==
+			       cpu_to_le16(XTENTRYSTART + 1));
+			xad = &p->xad[XTENTRYSTART];
+			bn = addressXAD(xad);
+
+			/* get new child page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+
+			BT_MARK_DIRTY(mp, ip);
+			if (!test_cflag(COMMIT_Nolink, ip)) {
+				tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
+				xtlck = (struct xtlock *) & tlck->lock;
 			}
 		} else {
 			/* get back old page */
 			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
 
 			/* is nXAD on new page ? */
 			if (newindex >
@@ -2247,6 +2257,8 @@
 
 		/* get new right page */
 		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+		if (rc)
+			return rc;
 
 		BT_MARK_DIRTY(mp, ip);
 		if (!test_cflag(COMMIT_Nolink, ip)) {
@@ -2270,13 +2282,16 @@
 
 		if ((rc = xtSearch(ip, nxoff, &cmp, &btstack, XT_INSERT)))
 			return rc;
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
+
 		if (cmp != 0) {
+			XT_PUTPAGE(mp);
 			jfs_error(ip->i_sb, "xtUpdate: xtSearch failed");
 			return -EIO;
 		}
 
-		/* retrieve search result */
-		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
 		if (index0 != index) {
 			XT_PUTPAGE(mp);
 			jfs_error(ip->i_sb,
@@ -2325,25 +2340,27 @@
 		 * resides on the new child page;
 		 */
 		if (rootsplit) {
-			if (p->header.nextindex ==
-			    cpu_to_le16(XTENTRYSTART + 1)) {
-				xad = &p->xad[XTENTRYSTART];
-				bn = addressXAD(xad);
-
-				/* get new child page */
-				XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
-
-				BT_MARK_DIRTY(mp, ip);
-				if (!test_cflag(COMMIT_Nolink, ip)) {
-					tlck = txLock(tid, ip, mp,
-						      tlckXTREE |
-						      tlckGROW);
-					xtlck = (struct xtlock *) & tlck->lock;
-				}
+			ASSERT(p->header.nextindex ==
+			       cpu_to_le16(XTENTRYSTART + 1));
+			xad = &p->xad[XTENTRYSTART];
+			bn = addressXAD(xad);
+
+			/* get new child page */
+			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+
+			BT_MARK_DIRTY(mp, ip);
+			if (!test_cflag(COMMIT_Nolink, ip)) {
+				tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
+				xtlck = (struct xtlock *) & tlck->lock;
 			}
-		} else
+		} else {
 			/* get back old page */
 			XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
+			if (rc)
+				return rc;
+		}
 	} else {
 		/* if insert into middle, shift right remaining entries */
 		if (newindex < nextindex)
@@ -2660,8 +2677,10 @@
 	/*
 	 * free non-root leaf page
 	 */
-	if ((rc = xtRelink(tid, ip, fp)))
+	if ((rc = xtRelink(tid, ip, fp))) {
+		XT_PUTPAGE(fmp);
 		return rc;
+	}
 
 	xaddr = addressPXD(&fp->header.self);
 	xlen = lengthPXD(&fp->header.self);
@@ -2703,7 +2722,7 @@
 				p->header.nextindex =
 				    cpu_to_le16(XTENTRYSTART);
 
-				/* XT_PUTPAGE(fmp); */
+				/* XT_PUTPAGE(mp); */
 
 				break;
 			} else {
@@ -2717,7 +2736,7 @@
 				       (s64) JFS_SBI(ip->i_sb)->nbperpage);
 
 				/* unpin/free the buffer page */
-				discard_metapage(fmp);
+				discard_metapage(mp);
 
 				/* propagate up */
 				continue;
@@ -2826,14 +2845,15 @@
 		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
 		if (rc)
 			return rc;
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+
 		if (cmp) {
 			XT_PUTPAGE(pmp);
 			return -ESTALE;
 		}
 
-		/* retrieve search result */
-		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
-
 		/* validate for exact match with a single entry */
 		xad = &pp->xad[index];
 		if (addressXAD(xad) != oxaddr || lengthXAD(xad) != xlen) {
@@ -2846,14 +2866,15 @@
 		rc = xtSearchNode(ip, oxad, &cmp, &btstack, 0);
 		if (rc)
 			return rc;
+
+		/* retrieve search result */
+		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
+
 		if (cmp) {
 			XT_PUTPAGE(pmp);
 			return -ESTALE;
 		}
 
-		/* retrieve search result */
-		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
-
 		/* xtSearchNode() validated for exact match with a single entry
 		 */
 		xad = &pp->xad[index];
@@ -2927,7 +2948,9 @@
 		}
 
 		/* get back parent page */
-		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
+		if ((rc = xtSearch(ip, xoff, &cmp, &btstack, 0)))
+			return rc;
+
 		XT_GETSEARCH(ip, btstack.top, bn, pmp, pp, index);
 		jfs_info("xtRelocate: target data extent relocated.");
 	} else {		/* (xtype  == XTPAGE) */
@@ -3150,8 +3173,10 @@
 		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
 		if (rc)
 			return rc;
-		if (p->header.flag & BT_LEAF)
+		if (p->header.flag & BT_LEAF) {
+			XT_PUTPAGE(mp);
 			return -ESTALE;
+		}
 
 		lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
 
@@ -3949,12 +3974,15 @@
 		rc = xtSearch(ip, xoff, &cmp, &btstack, 0);
 		if (rc)
 			return rc;
+
+		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
+
 		if (cmp != 0) {
+			XT_PUTPAGE(mp);
 			jfs_error(ip->i_sb,
 				  "xtTruncate_pmap: did not find extent");
 			return -EIO;
 		}
-		XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
 	} else {
 		/*
 		 * start with root
@@ -4202,16 +4230,9 @@
 int xtDisplayPage(struct inode *ip, s64 bn, xtpage_t * p)
 {
 	int rc = 0;
-	struct metapage *mp;
 	xad_t *xad;
 	s64 xaddr, xoff;
 	int xlen, i, j;
-
-	if (p == NULL) {
-		XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
-		if (rc)
-			return rc;
-	}
 
 	/* display page control */
 	printf("bn:0x%lx flag:0x%x nextindex:%d\n",
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Sat Apr  3 19:38:43 2004
+++ b/fs/jfs/super.c	Sat Apr  3 19:38:43 2004
@@ -548,11 +548,11 @@
 
 	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
+		memset(jfs_ip, 0, sizeof(struct jfs_inode_info));
 		INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
 		init_rwsem(&jfs_ip->rdwrlock);
 		init_MUTEX(&jfs_ip->commit_sem);
 		init_rwsem(&jfs_ip->xattr_sem);
-		jfs_ip->atlhead = 0;
 		jfs_ip->active_ag = -1;
 #ifdef CONFIG_JFS_POSIX_ACL
 		jfs_ip->i_acl = JFS_ACL_NOT_CACHED;
diff -Nru a/fs/libfs.c b/fs/libfs.c
--- a/fs/libfs.c	Sat Apr  3 19:38:40 2004
+++ b/fs/libfs.c	Sat Apr  3 19:38:40 2004
@@ -155,7 +155,6 @@
 			}
 			spin_unlock(&dcache_lock);
 	}
-	update_atime(dentry->d_inode);
 	return 0;
 }
 
diff -Nru a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
--- a/fs/lockd/clntproc.c	Sat Apr  3 19:38:40 2004
+++ b/fs/lockd/clntproc.c	Sat Apr  3 19:38:40 2004
@@ -443,7 +443,7 @@
 		}
 		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 -Nru a/fs/lockd/host.c b/fs/lockd/host.c
--- a/fs/lockd/host.c	Sat Apr  3 19:38:43 2004
+++ b/fs/lockd/host.c	Sat Apr  3 19:38:43 2004
@@ -188,14 +188,14 @@
 		}
 	} 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 -Nru a/fs/lockd/mon.c b/fs/lockd/mon.c
--- a/fs/lockd/mon.c	Sat Apr  3 19:38:54 2004
+++ b/fs/lockd/mon.c	Sat Apr  3 19:38:54 2004
@@ -36,10 +36,11 @@
 	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 @@
 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 @@
 	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 -Nru a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
--- a/fs/lockd/svc4proc.c	Sat Apr  3 19:38:42 2004
+++ b/fs/lockd/svc4proc.c	Sat Apr  3 19:38:42 2004
@@ -453,6 +453,24 @@
 }
 
 /*
+ * 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 @@
 #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 @@
   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 -Nru a/fs/lockd/svclock.c b/fs/lockd/svclock.c
--- a/fs/lockd/svclock.c	Sat Apr  3 19:38:42 2004
+++ b/fs/lockd/svclock.c	Sat Apr  3 19:38:42 2004
@@ -64,7 +64,7 @@
 	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 @@
  * 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 @@
 	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 @@
  * 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 -Nru a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
--- a/fs/lockd/svcproc.c	Sat Apr  3 19:38:45 2004
+++ b/fs/lockd/svcproc.c	Sat Apr  3 19:38:45 2004
@@ -479,6 +479,22 @@
 }
 
 /*
+ * 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 @@
 #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 @@
   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 -Nru a/fs/minix/dir.c b/fs/minix/dir.c
--- a/fs/minix/dir.c	Sat Apr  3 19:38:54 2004
+++ b/fs/minix/dir.c	Sat Apr  3 19:38:54 2004
@@ -127,7 +127,6 @@
 
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
-	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	Sat Apr  3 19:38:42 2004
+++ b/fs/namei.c	Sat Apr  3 19:38:42 2004
@@ -412,7 +412,7 @@
 		goto loop;
 	current->link_count++;
 	current->total_link_count++;
-	update_atime(dentry->d_inode);
+	touch_atime(nd->mnt, dentry);
 	err = dentry->d_inode->i_op->follow_link(dentry, nd);
 	current->link_count--;
 	return err;
@@ -1368,7 +1368,7 @@
 	error = security_inode_follow_link(dentry, nd);
 	if (error)
 		goto exit_dput;
-	update_atime(dentry->d_inode);
+	touch_atime(nd->mnt, dentry);
 	error = dentry->d_inode->i_op->follow_link(dentry, nd);
 	dput(dentry);
 	if (error)
diff -Nru a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c	Sat Apr  3 19:38:45 2004
+++ b/fs/namespace.c	Sat Apr  3 19:38:45 2004
@@ -681,6 +681,10 @@
 	if (nd->mnt->mnt_sb == mnt->mnt_sb && nd->mnt->mnt_root == nd->dentry)
 		goto unlock;
 
+	err = -EINVAL;
+	if (S_ISLNK(mnt->mnt_root->d_inode->i_mode))
+		goto unlock;
+
 	mnt->mnt_flags = mnt_flags;
 	err = graft_tree(mnt, nd);
 unlock:
@@ -690,7 +694,7 @@
 	return err;
 }
 
-static int copy_mount_options (const void __user *data, unsigned long *where)
+int copy_mount_options (const void __user *data, unsigned long *where)
 {
 	int i;
 	unsigned long page;
diff -Nru a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
--- a/fs/ncpfs/inode.c	Sat Apr  3 19:38:43 2004
+++ b/fs/ncpfs/inode.c	Sat Apr  3 19:38:43 2004
@@ -479,6 +479,7 @@
 	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 -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Sat Apr  3 19:38:43 2004
+++ b/fs/nfs/dir.c	Sat Apr  3 19:38:43 2004
@@ -139,11 +139,13 @@
 	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 @@
 		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 @@
 						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 @@
 			}
 			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 @@
  * 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 @@
 	/* 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 @@
 	int error;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
+	unsigned long verifier;
 	int isopen = 0;
 
 	parent = dget_parent(dentry);
@@ -574,6 +592,9 @@
 		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 @@
 		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 @@
 
  out_valid_renew:
 	nfs_renew_times(dentry);
+	nfs_set_verifier(dentry, verifier);
  out_valid:
 	unlock_kernel();
 	dput(parent);
@@ -638,6 +666,11 @@
 		/* 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 @@
 	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 @@
 	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 @@
 
 	/* 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 @@
 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 @@
 {
 	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 @@
 	/* 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 @@
 	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 @@
 	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 @@
 	 * 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 @@
 	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 @@
 	 */
 	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 @@
 		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 @@
 			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 @@
 		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 @@
 	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 @@
 	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 @@
 	 */
 	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 @@
 	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 @@
 
 	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 -Nru a/fs/nfs/direct.c b/fs/nfs/direct.c
--- a/fs/nfs/direct.c	Sat Apr  3 19:38:55 2004
+++ b/fs/nfs/direct.c	Sat Apr  3 19:38:55 2004
@@ -269,6 +269,7 @@
 	if (IS_SYNC(inode) || NFS_PROTO(inode)->version == 2 || count <= wsize)
 		wdata.args.stable = NFS_FILE_SYNC;
 
+	nfs_begin_data_update(inode);
 retry:
 	need_commit = 0;
 	tot_bytes = 0;
@@ -334,6 +335,8 @@
 						VERF_SIZE) != 0)
 			goto sync_retry;
 	}
+	nfs_end_data_update(inode);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
 
 	return tot_bytes;
 
diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c	Sat Apr  3 19:38:45 2004
+++ b/fs/nfs/file.c	Sat Apr  3 19:38:45 2004
@@ -104,11 +104,16 @@
 
 	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 @@
 	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 -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Sat Apr  3 19:38:54 2004
+++ b/fs/nfs/inode.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 {
 	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 @@
 	cred = nfsi->cache_access.cred;
 	if (cred)
 		put_rpccred(cred);
+	BUG_ON(atomic_read(&nfsi->data_updates) != 0);
 }
 
 void
@@ -230,50 +228,23 @@
 /*
  * 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 @@
 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 @@
 
 	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 @@
 	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 @@
 	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 @@
 	/* 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 @@
 	return clnt;
 
 out_fail:
-	if (xprt)
-		xprt_destroy(xprt);
-	return NULL;
+	xprt_destroy(xprt);
+	return clnt;
 }
 
 /*
@@ -627,13 +592,17 @@
 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 @@
 		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 @@
 		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 @@
 		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 @@
 	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 @@
 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 @@
 	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 @@
 	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 @@
 {
 	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 @@
  		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 @@
 		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_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;
 
-	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:
+	/* Are we in the process of updating data on the server? */
+	data_unstable = nfs_caches_unstable(inode);
+
+	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 @@
  *
  * 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 @@
 	 *       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 @@
 		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 @@
 			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 @@
  		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 @@
 	.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 @@
 				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 @@
 	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 @@
 		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 @@
 
 	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 @@
 	.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 @@
 		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 -Nru a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
--- a/fs/nfs/mount_clnt.c	Sat Apr  3 19:38:41 2004
+++ b/fs/nfs/mount_clnt.c	Sat Apr  3 19:38:41 2004
@@ -57,8 +57,9 @@
 			(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 @@
 	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 -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Sat Apr  3 19:38:42 2004
+++ b/fs/nfs/nfs2xdr.c	Sat Apr  3 19:38:42 2004
@@ -36,33 +36,33 @@
  * 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_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_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_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 -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Sat Apr  3 19:38:43 2004
+++ b/fs/nfs/nfs3proc.c	Sat Apr  3 19:38:43 2004
@@ -68,20 +68,6 @@
 	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 @@
  */
 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 @@
 	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 @@
 	msg.rpc_cred = nfs_cred(inode, filp);
 	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
 	if (status >= 0)
-		nfs3_write_refresh_inode(inode, fattr);
+		nfs_refresh_inode(inode, fattr);
 	dprintk("NFS reply commit: %d\n", status);
 	return status;
 }
@@ -777,12 +767,13 @@
 static void
 nfs3_write_done(struct rpc_task *task)
 {
-	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	struct nfs_write_data *data;
 
 	if (nfs3_async_handle_jukebox(task))
 		return;
+	data = (struct nfs_write_data *)task->tk_calldata;
 	if (task->tk_status >= 0)
-		nfs3_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_writeback_done(task);
 }
 
@@ -835,12 +826,13 @@
 static void
 nfs3_commit_done(struct rpc_task *task)
 {
-	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
+	struct nfs_write_data *data;
 
 	if (nfs3_async_handle_jukebox(task))
 		return;
+	data = (struct nfs_write_data *)task->tk_calldata;
 	if (task->tk_status >= 0)
-		nfs3_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_commit_done(task);
 }
 
diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
--- a/fs/nfs/nfs3xdr.c	Sat Apr  3 19:38:57 2004
+++ b/fs/nfs/nfs3xdr.c	Sat Apr  3 19:38:57 2004
@@ -33,51 +33,51 @@
  * 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_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_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 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 -Nru a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
--- a/fs/nfs/nfs4proc.c	Sat Apr  3 19:38:54 2004
+++ b/fs/nfs/nfs4proc.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 
 	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 @@
 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 @@
 
 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 @@
 		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_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 @@
 
 	if (status >= 0)
 		status = nfs_refresh_inode(dir, &dir_attr);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1016,7 +1033,7 @@
 		else if (req_access != resp_access)
 			status = -EACCES;
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 /*
@@ -1052,7 +1069,7 @@
 	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
@@ -1088,14 +1105,10 @@
 
 	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
@@ -1130,9 +1143,8 @@
 
 	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
@@ -1167,7 +1179,7 @@
 	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 +1246,7 @@
 		process_cinfo(&dir_cinfo, &dir_attr);
 		nfs_refresh_inode(dir, &dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 struct unlink_desc {
@@ -1312,7 +1324,7 @@
 		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 +1354,7 @@
 		nfs_refresh_inode(dir, &dir_attr);
 		nfs_refresh_inode(inode, &fattr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1373,7 +1385,7 @@
 		process_cinfo(&dir_cinfo, &dir_attr);
 		nfs_refresh_inode(dir, &dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1403,7 +1415,7 @@
 		process_cinfo(&dir_cinfo, &dir_attr);
 		nfs_refresh_inode(dir, &dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1421,9 +1433,11 @@
 	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 +1467,7 @@
 		process_cinfo(&dir_cinfo, &dir_attr);
 		nfs_refresh_inode(dir, &dir_attr);
 	}
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -1463,11 +1477,10 @@
 	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 +1493,7 @@
 		.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,11 +1503,10 @@
 	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);
+	return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0));
 }
 
 static void
@@ -1517,7 +1528,6 @@
 {
 	struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
 	struct inode *inode = data->inode;
-	struct nfs_fattr *fattr = data->res.fattr;
 
 	if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
 		task->tk_action = nfs4_restart_read;
@@ -1525,11 +1535,6 @@
 	}
 	if (task->tk_status > 0)
 		renew_lease(NFS_SERVER(inode), data->timestamp);
-	/* Check cache consistency */
-	if (fattr->change_attr != NFS_CHANGE_ATTR(inode))
-		nfs_zap_caches(inode);
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_ACCESS)
-		inode->i_atime = fattr->atime;
 	/* Call back common NFS readpage processing */
 	nfs_readpage_result(task);
 }
@@ -1577,21 +1582,6 @@
 }
 
 static void
-nfs4_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
-{
-	/* Check cache consistency */
-	if (fattr->pre_change_attr != NFS_CHANGE_ATTR(inode))
-		nfs_zap_caches(inode);
-	NFS_CHANGE_ATTR(inode) = fattr->change_attr;
-	if (fattr->bitmap[1] & FATTR4_WORD1_SPACE_USED)
-		inode->i_blocks = (fattr->du.nfs3.used + 511) >> 9;
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_METADATA)
-		inode->i_ctime = fattr->ctime;
-	if (fattr->bitmap[1] & FATTR4_WORD1_TIME_MODIFY)
-		inode->i_mtime = fattr->mtime;
-}
-
-static void
 nfs4_restart_write(struct rpc_task *task)
 {
 	struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
@@ -1617,7 +1607,6 @@
 	}
 	if (task->tk_status >= 0)
 		renew_lease(NFS_SERVER(inode), data->timestamp);
-	nfs4_write_refresh_inode(inode, data->res.fattr);
 	/* Call back common NFS writeback processing */
 	nfs_writeback_done(task);
 }
@@ -1684,7 +1673,6 @@
 		task->tk_action = nfs4_restart_write;
 		return;
 	}
-	nfs4_write_refresh_inode(inode, data->res.fattr);
 	/* Call back common NFS writeback processing */
 	nfs_commit_done(task);
 }
@@ -1807,6 +1795,7 @@
 	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 +1812,11 @@
 
 	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 +1844,7 @@
 {
 	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 +1863,7 @@
 			task->tk_status = 0;
 			return -EAGAIN;
 	}
+	task->tk_status = nfs4_map_errors(task->tk_status);
 	return 0;
 }
 
@@ -1946,16 +1941,9 @@
 			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 +2118,7 @@
 	if (lsp)
 		nfs4_put_lock_state(lsp);
 	up(&state->lock_sema);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 int
@@ -2175,7 +2163,7 @@
 	nfs4_put_lock_state(lsp);
 out:
 	up(&state->lock_sema);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
@@ -2251,7 +2239,7 @@
 	nfs4_put_lock_state(lsp);
 out:
 	up(&state->lock_sema);
-	return status;
+	return nfs4_map_errors(status);
 }
 
 static int
diff -Nru a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
--- a/fs/nfs/nfs4state.c	Sat Apr  3 19:38:40 2004
+++ b/fs/nfs/nfs4state.c	Sat Apr  3 19:38:40 2004
@@ -411,18 +411,20 @@
 	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 @@
 }
 
 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 @@
 		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 @@
 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 -Nru a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
--- a/fs/nfs/nfs4xdr.c	Sat Apr  3 19:38:56 2004
+++ b/fs/nfs/nfs4xdr.c	Sat Apr  3 19:38:56 2004
@@ -69,84 +69,84 @@
 /* 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 @@
                                 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 @@
 
 	dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
 	BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
-	RESERVE_SPACE(12+XDR_QUADLEN(hdr->taglen));
+	RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2));
 	WRITE32(hdr->taglen);
 	WRITEMEM(hdr->tag, hdr->taglen);
 	WRITE32(NFS4_MINOR_VERSION);
@@ -3165,6 +3165,10 @@
 	{ 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		}
 };
 
@@ -3179,6 +3183,10 @@
 	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
 		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.
diff -Nru a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
--- a/fs/nfs/nfsroot.c	Sat Apr  3 19:38:54 2004
+++ b/fs/nfs/nfsroot.c	Sat Apr  3 19:38:54 2004
@@ -166,37 +166,6 @@
 
 
 /*
- *  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 @@
 			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 -Nru a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
--- a/fs/nfs/pagelist.c	Sat Apr  3 19:38:55 2004
+++ b/fs/nfs/pagelist.c	Sat Apr  3 19:38:55 2004
@@ -246,7 +246,6 @@
  * nfs_scan_list - Scan a list for matching requests
  * @head: One of the NFS inode request lists
  * @dst: Destination list
- * @file: if set, ensure we match requests from this file
  * @idx_start: lower bound of page->index to scan
  * @npages: idx_start + npages sets the upper bound to scan.
  *
@@ -258,7 +257,6 @@
  */
 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;
@@ -275,9 +273,6 @@
 	list_for_each_safe(pos, tmp, head) {
 
 		req = nfs_list_entry(pos);
-
-		if (file && req->wb_file != file)
-			continue;
 
 		if (req->wb_index < idx_start)
 			continue;
diff -Nru a/fs/nfs/proc.c b/fs/nfs/proc.c
--- a/fs/nfs/proc.c	Sat Apr  3 19:38:55 2004
+++ b/fs/nfs/proc.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
  */
 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 @@
 	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 @@
 	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 @@
 {
 	struct rpc_message *msg = &task->tk_msg;
 	
-	if (msg->rpc_argp) {
-		NFS_CACHEINV(dir->d_inode);
+	if (msg->rpc_argp)
 		kfree(msg->rpc_argp);
-	}
 	return 0;
 }
 
@@ -537,8 +547,14 @@
 {
 	struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
 
-	if (task->tk_status >= 0)
+	if (task->tk_status >= 0) {
 		nfs_refresh_inode(data->inode, data->res.fattr);
+		/* Emulate the eof flag, which isn't normally needed in NFSv2
+		 * as it is guaranteed to always return the file attributes
+		 */
+		if (data->args.offset + data->args.count >= data->res.fattr->size)
+			data->res.eof = 1;
+	}
 	nfs_readpage_result(task);
 }
 
@@ -584,7 +600,7 @@
 	struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
 
 	if (task->tk_status >= 0)
-		nfs_write_refresh_inode(data->inode, data->res.fattr);
+		nfs_refresh_inode(data->inode, data->res.fattr);
 	nfs_writeback_done(task);
 }
 
diff -Nru a/fs/nfs/read.c b/fs/nfs/read.c
--- a/fs/nfs/read.c	Sat Apr  3 19:38:40 2004
+++ b/fs/nfs/read.c	Sat Apr  3 19:38:40 2004
@@ -121,9 +121,13 @@
 		}
 		count -= result;
 		rdata.args.pgbase += result;
-		if (result < rdata.args.count)	/* NFSv2ism */
+		/* Note: result == 0 should only happen if we're caching
+		 * a write that extends the file and punches a hole.
+		 */
+		if (rdata.res.eof != 0 || result == 0)
 			break;
 	} while (count);
+	NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
 
 	if (count)
 		memclear_highpage_flush(page, rdata.args.pgbase, count);
@@ -266,6 +270,7 @@
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
 		task->tk_pid, task->tk_status);
 
+	NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME;
 	while (!list_empty(&data->pages)) {
 		struct nfs_page *req = nfs_list_entry(data->pages.next);
 		struct page *page = req->wb_page;
diff -Nru a/fs/nfs/unlink.c b/fs/nfs/unlink.c
--- a/fs/nfs/unlink.c	Sat Apr  3 19:38:55 2004
+++ b/fs/nfs/unlink.c	Sat Apr  3 19:38:55 2004
@@ -104,6 +104,7 @@
 	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 @@
 	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 -Nru a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c	Sat Apr  3 19:38:54 2004
+++ b/fs/nfs/write.c	Sat Apr  3 19:38:54 2004
@@ -74,7 +74,6 @@
 static struct nfs_page * nfs_update_request(struct file*, struct inode *,
 					    struct page *,
 					    unsigned int, unsigned int);
-static void	nfs_strategy(struct inode *inode);
 
 static kmem_cache_t *nfs_wdata_cachep;
 static mempool_t *nfs_wdata_mempool;
@@ -124,6 +123,52 @@
 	nfs_commit_free(wdata);
 }
 
+/* Adjust the file length if we're writing beyond the end */
+static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
+{
+	struct inode *inode = page->mapping->host;
+	loff_t end, i_size = i_size_read(inode);
+	unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
+
+	if (i_size > 0 && page->index < end_index)
+		return;
+	end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
+	if (i_size >= end)
+		return;
+	i_size_write(inode, end);
+}
+
+/* We can set the PG_uptodate flag if we see that a write request
+ * covers the full page.
+ */
+static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count)
+{
+	loff_t end_offs;
+
+	if (PageUptodate(page))
+		return;
+	if (base != 0)
+		return;
+	if (count == PAGE_CACHE_SIZE) {
+		SetPageUptodate(page);
+		return;
+	}
+
+	end_offs = i_size_read(page->mapping->host) - 1;
+	if (end_offs < 0)
+		return;
+	/* Is this the last page? */
+	if (page->index != (unsigned long)(end_offs >> PAGE_CACHE_SHIFT))
+		return;
+	/* This is the last page: set PG_uptodate if we cover the entire
+	 * extent of the data, then zero the rest of the page.
+	 */
+	if (count == (unsigned int)(end_offs & (PAGE_CACHE_SIZE - 1)) + 1) {
+		memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count);
+		SetPageUptodate(page);
+	}
+}
+
 /*
  * Write a page synchronously.
  * Offset is the data offset within the page.
@@ -157,6 +202,7 @@
 		(long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
+	nfs_begin_data_update(inode);
 	do {
 		if (count < wsize && !swapfile)
 			wdata.args.count = count;
@@ -177,43 +223,38 @@
 	        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;
 }
@@ -286,7 +327,7 @@
 	err = generic_writepages(mapping, wbc);
 	if (err)
 		goto out;
-	err = nfs_flush_file(inode, NULL, 0, 0, 0);
+	err = nfs_flush_inode(inode, 0, 0, 0);
 	if (err < 0)
 		goto out;
 	if (wbc->sync_mode == WB_SYNC_HOLD)
@@ -294,7 +335,7 @@
 	if (is_sync && wbc->sync_mode == WB_SYNC_ALL) {
 		err = nfs_wb_all(inode);
 	} else
-		nfs_commit_file(inode, NULL, 0, 0, 0);
+		nfs_commit_inode(inode, 0, 0, 0);
 out:
 	return err;
 }
@@ -312,8 +353,10 @@
 	BUG_ON(error == -EEXIST);
 	if (error)
 		return error;
-	if (!nfsi->npages)
+	if (!nfsi->npages) {
 		igrab(inode);
+		nfs_begin_data_update(inode);
+	}
 	nfsi->npages++;
 	req->wb_count++;
 	return 0;
@@ -336,6 +379,7 @@
 	nfsi->npages--;
 	if (!nfsi->npages) {
 		spin_unlock(&nfs_wreq_lock);
+		nfs_end_data_update(inode);
 		iput(inode);
 	} else
 		spin_unlock(&nfs_wreq_lock);
@@ -421,7 +465,7 @@
  * 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 +485,6 @@
 			break;
 
 		next = req->wb_index + 1;
-		if (file && req->wb_file != file)
-			continue;
 		if (!NFS_WBACK_BUSY(req))
 			continue;
 
@@ -453,7 +495,6 @@
 		if (error < 0)
 			return error;
 		spin_lock(&nfs_wreq_lock);
-		next = idx_start;
 		res++;
 	}
 	spin_unlock(&nfs_wreq_lock);
@@ -464,7 +505,6 @@
  * 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 +512,11 @@
  * 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 +529,6 @@
  * 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 +536,11 @@
  * The requests are *not* checked to ensure that they form a contiguous set.
  */
 static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
 	int	res;
-	res = nfs_scan_list(&nfsi->commit, dst, file, idx_start, npages);
+	res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);
 	nfsi->ncommit -= res;
 	if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
@@ -600,46 +639,6 @@
 	return req;
 }
 
-/*
- * This is the strategy routine for NFS.
- * It is called by nfs_updatepage whenever the user wrote up to the end
- * of a page.
- *
- * We always try to submit a set of requests in parallel so that the
- * server's write code can gather writes. This is mainly for the benefit
- * of NFSv2.
- *
- * We never submit more requests than we think the remote can handle.
- * For UDP sockets, we make sure we don't exceed the congestion window;
- * for TCP, we limit the number of requests to 8.
- *
- * NFS_STRATEGY_PAGES gives the minimum number of requests for NFSv2 that
- * should be sent out in one go. This is for the benefit of NFSv2 servers
- * that perform write gathering.
- *
- * FIXME: Different servers may have different sweet spots.
- * Record the average congestion window in server struct?
- */
-#define NFS_STRATEGY_PAGES      8
-static void
-nfs_strategy(struct inode *inode)
-{
-	unsigned int	dirty, wpages;
-
-	dirty  = NFS_I(inode)->ndirty;
-	wpages = NFS_SERVER(inode)->wpages;
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-	if (NFS_PROTO(inode)->version == 2) {
-		if (dirty >= NFS_STRATEGY_PAGES * wpages)
-			nfs_flush_file(inode, NULL, 0, 0, 0);
-	} else if (dirty >= wpages)
-		nfs_flush_file(inode, NULL, 0, 0, 0);
-#else
-	if (dirty >= NFS_STRATEGY_PAGES * wpages)
-		nfs_flush_file(inode, NULL, 0, 0, 0);
-#endif
-}
-
 int
 nfs_flush_incompatible(struct file *file, struct page *page)
 {
@@ -675,7 +674,6 @@
 	struct dentry	*dentry = file->f_dentry;
 	struct inode	*inode = page->mapping->host;
 	struct nfs_page	*req;
-	loff_t		end;
 	int		status = 0;
 
 	dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",
@@ -696,6 +694,27 @@
 		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 +733,12 @@
 		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));
@@ -891,10 +902,7 @@
 #endif
 
 	/*
-	 * Update attributes as result of writeback.
-	 * FIXME: There is an inherent race with invalidate_inode_pages and
-	 *	  writebacks since the page->count is kept > 1 for as long
-	 *	  as the page has a write request pending.
+	 * Process the nfs_page list
 	 */
 	while (!list_empty(&data->pages)) {
 		req = nfs_list_entry(data->pages.next);
@@ -1061,7 +1069,7 @@
 }
 #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 +1077,7 @@
 				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 +1087,7 @@
 }
 
 #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 +1095,9 @@
 				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 +1108,7 @@
 }
 #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 +1117,15 @@
 	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 -Nru a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
--- a/fs/nfsd/nfs3xdr.c	Sat Apr  3 19:38:40 2004
+++ b/fs/nfsd/nfs3xdr.c	Sat Apr  3 19:38:40 2004
@@ -884,10 +884,11 @@
 		if (plus) {
 			struct svc_fh	fh;
 
-			if (compose_entry_fh(cd, &fh, name, namlen) > 0)
-				goto noexec;
-
-			p = encode_entryplus_baggage(cd, p, &fh);
+			if (compose_entry_fh(cd, &fh, name, namlen) > 0) {
+				*p++ = 0;
+				*p++ = 0;
+			} else
+				p = encode_entryplus_baggage(cd, p, &fh);
 		}
 		num_entry_words = p - cd->buffer;
 	} else if (cd->rqstp->rq_respages[pn+1] != NULL) {
@@ -916,7 +917,7 @@
 		/* determine entry word length and lengths to go in pages */
 		num_entry_words = p1 - tmp;
 		len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
-		if ((num_entry_words << 2) <= len1) {
+		if ((num_entry_words << 2) < len1) {
 			/* the actual number of words in the entry is less
 			 * than elen and can still fit in the current page
 			 */
@@ -945,16 +946,11 @@
 		return -EINVAL;
 	}
 
-out:
 	cd->buflen -= num_entry_words;
 	cd->buffer = p;
 	cd->common.err = nfs_ok;
 	return 0;
 
-noexec:
-	*p++ = 0;
-	*p++ = 0;
-	goto out;
 }
 
 int
diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c	Sat Apr  3 19:38:42 2004
+++ b/fs/nfsd/vfs.c	Sat Apr  3 19:38:42 2004
@@ -1143,7 +1143,7 @@
 	if (!inode->i_op || !inode->i_op->readlink)
 		goto out;
 
-	update_atime(inode);
+	touch_atime(fhp->fh_export->ex_mnt, dentry);
 	/* N.B. Why does this call need a get_fs()??
 	 * Remove the set_fs and watch the fireworks:-) --okir
 	 */
diff -Nru a/fs/open.c b/fs/open.c
--- a/fs/open.c	Sat Apr  3 19:38:41 2004
+++ b/fs/open.c	Sat Apr  3 19:38:41 2004
@@ -954,6 +954,7 @@
 	fd = error;
 	goto out;
 }
+EXPORT_SYMBOL_GPL(sys_open);
 
 #ifndef __alpha__
 
diff -Nru a/fs/pipe.c b/fs/pipe.c
--- a/fs/pipe.c	Sat Apr  3 19:38:43 2004
+++ b/fs/pipe.c	Sat Apr  3 19:38:43 2004
@@ -165,7 +165,7 @@
 		kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT);
 	}
 	if (ret > 0)
-		update_atime(inode);
+		file_accessed(filp);
 	return ret;
 }
 
diff -Nru a/fs/proc/generic.c b/fs/proc/generic.c
--- a/fs/proc/generic.c	Sat Apr  3 19:38:56 2004
+++ b/fs/proc/generic.c	Sat Apr  3 19:38:56 2004
@@ -37,10 +37,6 @@
 	.write		= proc_file_write,
 };
 
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
 /* buffer size is one page but our output routines use some slack for overruns */
 #define PROC_BLOCK_SIZE	(PAGE_SIZE - 1024)
 
@@ -61,7 +57,7 @@
 		return -ENOMEM;
 
 	while ((nbytes > 0) && !eof) {
-		count = MIN(PROC_BLOCK_SIZE, nbytes);
+		count = min_t(ssize_t, PROC_BLOCK_SIZE, nbytes);
 
 		start = NULL;
 		if (dp->get_info) {
@@ -661,6 +657,7 @@
 			  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 -Nru a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c	Sat Apr  3 19:38:55 2004
+++ b/fs/proc/inode.c	Sat Apr  3 19:38:55 2004
@@ -231,6 +231,7 @@
 {
 	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 -Nru a/fs/proc/kmsg.c b/fs/proc/kmsg.c
--- a/fs/proc/kmsg.c	Sat Apr  3 19:38:56 2004
+++ b/fs/proc/kmsg.c	Sat Apr  3 19:38:56 2004
@@ -33,6 +33,8 @@
 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 -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Sat Apr  3 19:38:41 2004
+++ b/fs/proc/proc_misc.c	Sat Apr  3 19:38:41 2004
@@ -361,7 +361,8 @@
 	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 @@
 			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",
+
+		/* Copy values here to work around gcc-2.95.3, gcc-2.96 */
+		user = kstat_cpu(i).cpustat.user;
+		nice = kstat_cpu(i).cpustat.nice;
+		system = kstat_cpu(i).cpustat.system;
+		idle = kstat_cpu(i).cpustat.idle;
+		iowait = kstat_cpu(i).cpustat.iowait;
+		irq = kstat_cpu(i).cpustat.irq;
+		softirq = kstat_cpu(i).cpustat.softirq;
+		seq_printf(p, "cpu%d %llu %llu %llu %llu %llu %llu %llu\n",
 			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(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));
 	}
-	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 @@
 #endif
 
 	seq_printf(p,
-		"\nctxt %lu\n"
+		"\nctxt %llu\n"
 		"btime %lu\n"
 		"processes %lu\n"
 		"procs_running %lu\n"
diff -Nru a/fs/proc/root.c b/fs/proc/root.c
--- a/fs/proc/root.c	Sat Apr  3 19:38:54 2004
+++ b/fs/proc/root.c	Sat Apr  3 19:38:54 2004
@@ -74,9 +74,6 @@
 #ifdef CONFIG_PROC_DEVICETREE
 	proc_device_tree_init();
 #endif
-#ifdef CONFIG_PPC_RTAS
-	proc_rtas_init();
-#endif
 	proc_bus = proc_mkdir("bus", 0);
 }
 
diff -Nru a/fs/qnx4/dir.c b/fs/qnx4/dir.c
--- a/fs/qnx4/dir.c	Sat Apr  3 19:38:45 2004
+++ b/fs/qnx4/dir.c	Sat Apr  3 19:38:45 2004
@@ -76,8 +76,6 @@
 		}
 		brelse(bh);
 	}
-	update_atime(inode);
-
 out:
 	unlock_kernel();
 	return 0;
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c	Sat Apr  3 19:38:44 2004
+++ b/fs/read_write.c	Sat Apr  3 19:38:44 2004
@@ -143,6 +143,7 @@
 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 @@
 
 	return ret;
 }
+EXPORT_SYMBOL_GPL(sys_read);
 
 asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count)
 {
diff -Nru a/fs/readdir.c b/fs/readdir.c
--- a/fs/readdir.c	Sat Apr  3 19:38:43 2004
+++ b/fs/readdir.c	Sat Apr  3 19:38:43 2004
@@ -32,6 +32,7 @@
 	res = -ENOENT;
 	if (!IS_DEADDIR(inode)) {
 		res = file->f_op->readdir(file, buf, filler);
+		file_accessed(file);
 	}
 	up(&inode->i_sem);
 out:
@@ -161,7 +162,7 @@
 	if (__put_user(d_type, (char *) dirent + reclen - 1))
 		goto efault;
 	buf->previous = dirent;
-	dirent = (void *)dirent + reclen;
+	dirent = (void __user *)dirent + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
@@ -247,7 +248,7 @@
 	if (__put_user(0, dirent->d_name + namlen))
 		goto efault;
 	buf->previous = dirent;
-	dirent = (void *)dirent + reclen;
+	dirent = (void __user *)dirent + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
diff -Nru a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
--- a/fs/reiserfs/dir.c	Sat Apr  3 19:38:44 2004
+++ b/fs/reiserfs/dir.c	Sat Apr  3 19:38:44 2004
@@ -186,7 +186,6 @@
     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 -Nru a/fs/reiserfs/file.c b/fs/reiserfs/file.c
--- a/fs/reiserfs/file.c	Sat Apr  3 19:38:40 2004
+++ b/fs/reiserfs/file.c	Sat Apr  3 19:38:40 2004
@@ -365,7 +365,7 @@
     // 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 @@
 		    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 @@
 			/* 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 );
@@ -1060,7 +1064,10 @@
     if ( count == 0 )
 	goto out;
 
-    remove_suid(file->f_dentry);
+    res = remove_suid(file->f_dentry);
+    if (res)
+	goto out;
+
     inode_update_time(inode, 1); /* Both mtime and ctime */
 
     // Ok, we are done with all the checks.
@@ -1191,6 +1198,14 @@
     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 +1214,8 @@
     .release	= reiserfs_file_release,
     .fsync	= reiserfs_sync_file,
     .sendfile	= generic_file_sendfile,
+    .aio_read   = generic_file_aio_read,
+    .aio_write  = reiserfs_aio_write,
 };
 
 
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c	Sat Apr  3 19:38:42 2004
+++ b/fs/reiserfs/inode.c	Sat Apr  3 19:38:42 2004
@@ -209,7 +209,7 @@
   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 @@
         /* 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 -Nru a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
--- a/fs/reiserfs/stree.c	Sat Apr  3 19:38:54 2004
+++ b/fs/reiserfs/stree.c	Sat Apr  3 19:38:54 2004
@@ -652,8 +652,8 @@
                                        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 @@
     /* 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 @@
 	/* 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 @@
 	    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 @@
 	    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 @@
 	  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 -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c
--- a/fs/smbfs/inode.c	Sat Apr  3 19:38:41 2004
+++ b/fs/smbfs/inode.c	Sat Apr  3 19:38:41 2004
@@ -499,6 +499,7 @@
 	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 @@
 	.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 -Nru a/fs/smbfs/sock.c b/fs/smbfs/sock.c
--- a/fs/smbfs/sock.c	Sat Apr  3 19:38:42 2004
+++ b/fs/smbfs/sock.c	Sat Apr  3 19:38:42 2004
@@ -350,7 +350,7 @@
 	fs = get_fs();
 	set_fs(get_ds());
 
-	flags = MSG_DONTWAIT | MSG_NOSIGNAL;;
+	flags = MSG_DONTWAIT | MSG_NOSIGNAL;
 	msg.msg_flags = flags;
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
diff -Nru a/fs/stat.c b/fs/stat.c
--- a/fs/stat.c	Sat Apr  3 19:38:41 2004
+++ b/fs/stat.c	Sat Apr  3 19:38:41 2004
@@ -272,7 +272,7 @@
 		if (inode->i_op && inode->i_op->readlink) {
 			error = security_inode_readlink(nd.dentry);
 			if (!error) {
-				update_atime(inode);
+				touch_atime(nd.mnt, nd.dentry);
 				error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
 			}
 		}
diff -Nru a/fs/super.c b/fs/super.c
--- a/fs/super.c	Sat Apr  3 19:38:43 2004
+++ b/fs/super.c	Sat Apr  3 19:38:43 2004
@@ -636,7 +636,7 @@
 		char b[BDEVNAME_SIZE];
 
 		s->s_flags = flags;
-		strncpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
+		strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
 		s->s_old_blocksize = block_size(bdev);
 		sb_set_blocksize(s, s->s_old_blocksize);
 		error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
@@ -745,7 +745,7 @@
 			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 -Nru a/fs/sysfs/dir.c b/fs/sysfs/dir.c
--- a/fs/sysfs/dir.c	Sat Apr  3 19:38:43 2004
+++ b/fs/sysfs/dir.c	Sat Apr  3 19:38:43 2004
@@ -120,13 +120,14 @@
 	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 +138,12 @@
 			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 -Nru a/fs/sysfs/group.c b/fs/sysfs/group.c
--- a/fs/sysfs/group.c	Sat Apr  3 19:38:44 2004
+++ b/fs/sysfs/group.c	Sat Apr  3 19:38:44 2004
@@ -55,8 +55,8 @@
 	if ((error = create_files(dir,grp))) {
 		if (grp->name)
 			sysfs_remove_subdir(dir);
-		dput(dir);
 	}
+	dput(dir);
 	return error;
 }
 
@@ -68,12 +68,13 @@
 	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 -Nru a/fs/sysv/dir.c b/fs/sysv/dir.c
--- a/fs/sysv/dir.c	Sat Apr  3 19:38:42 2004
+++ b/fs/sysv/dir.c	Sat Apr  3 19:38:42 2004
@@ -116,7 +116,6 @@
 
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
-	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
diff -Nru a/fs/udf/dir.c b/fs/udf/dir.c
--- a/fs/udf/dir.c	Sat Apr  3 19:38:42 2004
+++ b/fs/udf/dir.c	Sat Apr  3 19:38:42 2004
@@ -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 @@
 	}
 
 	result = do_udf_readdir(dir, filp, filldir, dirent);
-	update_atime(dir);
 	unlock_kernel();
  	return result;
 }
@@ -112,7 +111,7 @@
 	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 -Nru a/fs/udf/file.c b/fs/udf/file.c
--- a/fs/udf/file.c	Sat Apr  3 19:38:44 2004
+++ b/fs/udf/file.c	Sat Apr  3 19:38:44 2004
@@ -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
diff -Nru a/fs/udf/inode.c b/fs/udf/inode.c
--- a/fs/udf/inode.c	Sat Apr  3 19:38:57 2004
+++ b/fs/udf/inode.c	Sat Apr  3 19:38:57 2004
@@ -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
@@ -130,15 +130,6 @@
 	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 @@
 		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 @@
 		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 @@
 
 		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 @@
 				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 @@
 		}
 		
 		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 @@
 
 		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 @@
 					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 @@
 				}
 			}
 		}
+		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 @@
 	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 @@
 		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 @@
 		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 @@
 			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 @@
 	}
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 		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 @@
 		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 -Nru a/fs/udf/misc.c b/fs/udf/misc.c
--- a/fs/udf/misc.c	Sat Apr  3 19:38:44 2004
+++ b/fs/udf/misc.c	Sat Apr  3 19:38:44 2004
@@ -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 @@
 
 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 @@
 			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 @@
 			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 @@
 			}
 		}
 		/* 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 @@
 		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;
 		}
 	
@@ -237,12 +193,6 @@
 			else
 				offset += le32_to_cpu(gaf->attrLength);
 		}
-	}
-
-	udf_release_data(*bh);
-	if (eaicb.extLength)
-	{
-		/* TODO */
 	}
 	return NULL;
 }
diff -Nru a/fs/udf/namei.c b/fs/udf/namei.c
--- a/fs/udf/namei.c	Sat Apr  3 19:38:55 2004
+++ b/fs/udf/namei.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 {
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 		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 @@
 {
 	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 @@
 {
 	struct inode * inode;
 	struct udf_fileident_bh fibh;
-	int err;
 	struct fileIdentDesc cfi, *fi;
+	int err;
 
 	lock_kernel();
 	err = -EMLINK;
@@ -1119,8 +1117,8 @@
 {
 	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 -Nru a/fs/udf/osta_udf.h b/fs/udf/osta_udf.h
--- a/fs/udf/osta_udf.h	Sat Apr  3 19:38:45 2004
+++ b/fs/udf/osta_udf.h	Sat Apr  3 19:38:45 2004
@@ -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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 
 #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 @@
 			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 @@
 
 #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 @@
 	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 @@
 #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 -Nru a/fs/udf/super.c b/fs/udf/super.c
--- a/fs/udf/super.c	Sat Apr  3 19:38:45 2004
+++ b/fs/udf/super.c	Sat Apr  3 19:38:45 2004
@@ -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 @@
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 		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 -Nru a/fs/udf/truncate.c b/fs/udf/truncate.c
--- a/fs/udf/truncate.c	Sat Apr  3 19:38:42 2004
+++ b/fs/udf/truncate.c	Sat Apr  3 19:38:42 2004
@@ -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
@@ -64,6 +64,67 @@
 				udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block);
 		}
 	}
+}
+
+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)
diff -Nru a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
--- a/fs/udf/udf_sb.h	Sat Apr  3 19:38:55 2004
+++ b/fs/udf/udf_sb.h	Sat Apr  3 19:38:55 2004
@@ -64,13 +64,14 @@
 {\
 	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 @@
 	}\
 }
 
+#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 @@
 #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 -Nru a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
--- a/fs/udf/udfdecl.h	Sat Apr  3 19:38:43 2004
+++ b/fs/udf/udfdecl.h	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	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 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_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 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 -Nru a/fs/udf/unicode.c b/fs/udf/unicode.c
--- a/fs/udf/unicode.c	Sat Apr  3 19:38:55 2004
+++ b/fs/udf/unicode.c	Sat Apr  3 19:38:55 2004
@@ -36,7 +36,7 @@
 
 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 @@
 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 @@
 	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 @@
 {
 	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 @@
 		}
 		
 		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 -Nru a/fs/ufs/dir.c b/fs/ufs/dir.c
--- a/fs/ufs/dir.c	Sat Apr  3 19:38:55 2004
+++ b/fs/ufs/dir.c	Sat Apr  3 19:38:55 2004
@@ -166,7 +166,6 @@
 		offset = 0;
 		brelse (bh);
 	}
-	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
diff -Nru a/fs/ufs/inode.c b/fs/ufs/inode.c
--- a/fs/ufs/inode.c	Sat Apr  3 19:38:41 2004
+++ b/fs/ufs/inode.c	Sat Apr  3 19:38:41 2004
@@ -82,7 +82,12 @@
 	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 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 @@
 	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 @@
 			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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 		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));
 
 	/*
@@ -563,6 +630,78 @@
 
 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;
 }
 
diff -Nru a/fs/ufs/namei.c b/fs/ufs/namei.c
--- a/fs/ufs/namei.c	Sat Apr  3 19:38:57 2004
+++ b/fs/ufs/namei.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Sat Apr  3 19:38:40 2004
+++ b/fs/ufs/super.c	Sat Apr  3 19:38:40 2004
@@ -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 @@
 	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 @@
 
 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 @@
 	{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 @@
 			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 @@
 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 @@
 		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 @@
 	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 @@
 		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 @@
 		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 @@
 	/*
 	 * 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 @@
 	}
 
 #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 @@
 	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 @@
 {
 	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 -Nru a/fs/ufs/util.c b/fs/ufs/util.c
--- a/fs/ufs/util.c	Sat Apr  3 19:38:43 2004
+++ b/fs/ufs/util.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 }
 
 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 -Nru a/fs/ufs/util.h b/fs/ufs/util.h
--- a/fs/ufs/util.h	Sat Apr  3 19:38:43 2004
+++ b/fs/ufs/util.h	Sat Apr  3 19:38:43 2004
@@ -228,8 +228,8 @@
  * 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 -Nru a/fs/xfs/linux/kmem.h b/fs/xfs/linux/kmem.h
--- a/fs/xfs/linux/kmem.h	Sat Apr  3 19:38:57 2004
+++ b/fs/xfs/linux/kmem.h	Sat Apr  3 19:38:57 2004
@@ -55,15 +55,23 @@
 
 typedef unsigned long xfs_pflags_t;
 
-#define PFLAGS_TEST_FSTRANS()		(current->flags & PF_FSTRANS)
+#define PFLAGS_TEST_FSTRANS()           (current->flags & PF_FSTRANS)
 
+/* these could be nested, so we save state */
 #define PFLAGS_SET_FSTRANS(STATEP) do {	\
 	*(STATEP) = current->flags;	\
 	current->flags |= PF_FSTRANS;	\
 } while (0)
 
-#define PFLAGS_RESTORE(STATEP) do {	\
-	current->flags = *(STATEP);	\
+#define PFLAGS_CLEAR_FSTRANS(STATEP) do { \
+	*(STATEP) = current->flags;	\
+	current->flags &= ~PF_FSTRANS;	\
+} while (0)
+
+/* Restore the PF_FSTRANS state to what was saved in STATEP */
+#define PFLAGS_RESTORE_FSTRANS(STATEP) do {     		\
+	current->flags = ((current->flags & ~PF_FSTRANS) |	\
+			  (*(STATEP) & PF_FSTRANS));		\
 } while (0)
 
 #define PFLAGS_DUP(OSTATEP, NSTATEP) do { \
diff -Nru a/fs/xfs/linux/mrlock.h b/fs/xfs/linux/mrlock.h
--- a/fs/xfs/linux/mrlock.h	Sat Apr  3 19:38:44 2004
+++ b/fs/xfs/linux/mrlock.h	Sat Apr  3 19:38:44 2004
@@ -88,6 +88,7 @@
 	downgrade_write(&mrp->mr_lock);
 }
 
+#ifdef DEBUG
 /*
  * Debug-only routine, without some platform-specific asm code, we can
  * now only answer requests regarding whether we hold the lock for write
@@ -96,9 +97,10 @@
  */
 static inline int ismrlocked(mrlock_t *mrp, int type)
 {
-	if (type == MR_UPDATE)
+	if (mrp && type == MR_UPDATE)
 		return mrp->mr_writer;
 	return 1;
 }
+#endif
 
 #endif /* __XFS_SUPPORT_MRLOCK_H__ */
diff -Nru a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c
--- a/fs/xfs/linux/xfs_aops.c	Sat Apr  3 19:38:55 2004
+++ b/fs/xfs/linux/xfs_aops.c	Sat Apr  3 19:38:55 2004
@@ -717,7 +717,8 @@
 	struct buffer_head	*bh_arr[MAX_BUF_PER_PAGE], *bh, *head;
 	xfs_iomap_t		*iomp, iomap;
 	unsigned long		p_offset = 0, end_index;
-	loff_t			offset, end_offset;
+	loff_t			offset;
+	unsigned long long	end_offset;
 	int			len, err, i, cnt = 0, uptodate = 1;
 	int			flags = startio ? 0 : BMAPI_TRYLOCK;
 	int			page_dirty = 1;
@@ -734,9 +735,8 @@
 	}
 
 	offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
-	end_offset = offset + PAGE_CACHE_SIZE;
-	if (end_offset > i_size_read(inode))
-		end_offset = i_size_read(inode);
+	end_offset = min_t(unsigned long long,
+			offset + PAGE_CACHE_SIZE, i_size_read(inode));
 
 	bh = head = page_buffers(page);
 	iomp = NULL;
diff -Nru a/fs/xfs/linux/xfs_file.c b/fs/xfs/linux/xfs_file.c
--- a/fs/xfs/linux/xfs_file.c	Sat Apr  3 19:38:43 2004
+++ b/fs/xfs/linux/xfs_file.c	Sat Apr  3 19:38:43 2004
@@ -68,16 +68,15 @@
 {
 	struct iovec		iov = {buf, count};
 	struct file		*file = iocb->ki_filp;
-	vnode_t			*vp;
-	int			error;
+	vnode_t			*vp = LINVFS_GET_VP(file->f_dentry->d_inode);
+	ssize_t			rval;
 
 	BUG_ON(iocb->ki_pos != pos);
 
 	if (unlikely(file->f_flags & O_DIRECT))
 		ioflags |= IO_ISDIRECT;
-	vp = LINVFS_GET_VP(file->f_dentry->d_inode);
-	VOP_READ(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, error);
-	return error;
+	VOP_READ(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL, rval);
+	return rval;
 }
 
 
@@ -114,20 +113,21 @@
 	struct file	*file = iocb->ki_filp;
 	struct inode	*inode = file->f_mapping->host;
 	vnode_t		*vp = LINVFS_GET_VP(inode);
-	int		error;
+	ssize_t		rval;
 
 	BUG_ON(iocb->ki_pos != pos);
 	if (unlikely(file->f_flags & O_DIRECT)) {
 		ioflags |= IO_ISDIRECT;
 		VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos,
-				ioflags, NULL, error);
+				ioflags, NULL, rval);
 	} else {
 		down(&inode->i_sem);
 		VOP_WRITE(vp, iocb, &iov, 1, &iocb->ki_pos,
-				ioflags, NULL, error);
+				ioflags, NULL, rval);
 		up(&inode->i_sem);
 	}
-	return error;
+
+	return rval;
 }
 
 
@@ -163,19 +163,19 @@
 	struct inode	*inode = file->f_mapping->host;
 	vnode_t		*vp = LINVFS_GET_VP(inode);
 	struct		kiocb kiocb;
-	int		error;
+	ssize_t		rval;
 
 	init_sync_kiocb(&kiocb, file);
 	kiocb.ki_pos = *ppos;
 
 	if (unlikely(file->f_flags & O_DIRECT))
 		ioflags |= IO_ISDIRECT;
-	VOP_READ(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, error);
-	if (-EIOCBQUEUED == error)
-		error = wait_on_sync_kiocb(&kiocb);
-	*ppos = kiocb.ki_pos;
+	VOP_READ(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos, ioflags, NULL, rval);
+	if (rval == -EIOCBQUEUED)
+		rval = wait_on_sync_kiocb(&kiocb);
 
-	return error;
+	*ppos = kiocb.ki_pos;
+	return rval;
 }
 
 STATIC ssize_t
@@ -210,25 +210,26 @@
 	struct inode	*inode = file->f_mapping->host;
 	vnode_t		*vp = LINVFS_GET_VP(inode);
 	struct		kiocb kiocb;
-	int		error;
+	ssize_t		rval;
 
 	init_sync_kiocb(&kiocb, file);
 	kiocb.ki_pos = *ppos;
 	if (unlikely(file->f_flags & O_DIRECT)) {
 		ioflags |= IO_ISDIRECT;
 		VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos,
-				ioflags, NULL, error);
+				ioflags, NULL, rval);
 	} else {
 		down(&inode->i_sem);
 		VOP_WRITE(vp, &kiocb, iov, nr_segs, &kiocb.ki_pos,
-				ioflags, NULL, error);
+				ioflags, NULL, rval);
 		up(&inode->i_sem);
 	}
-	if (-EIOCBQUEUED == error)
-		error = wait_on_sync_kiocb(&kiocb);
-	*ppos = kiocb.ki_pos;
 
-	return error;
+	if (rval == -EIOCBQUEUED)
+		rval = wait_on_sync_kiocb(&kiocb);
+
+	*ppos = kiocb.ki_pos;
+	return rval;
 }
 
 
diff -Nru a/fs/xfs/linux/xfs_ioctl.c b/fs/xfs/linux/xfs_ioctl.c
--- a/fs/xfs/linux/xfs_ioctl.c	Sat Apr  3 19:38:54 2004
+++ b/fs/xfs/linux/xfs_ioctl.c	Sat Apr  3 19:38:54 2004
@@ -850,6 +850,9 @@
 	case XFS_IOC_ERROR_INJECTION: {
 		xfs_error_injection_t in;
 
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
 		if (copy_from_user(&in, (char *)arg, sizeof(in)))
 			return -XFS_ERROR(EFAULT);
 
@@ -858,6 +861,9 @@
 	}
 
 	case XFS_IOC_ERROR_CLEARALL:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+
 		error = xfs_errortag_clearall(mp);
 		return -error;
 
@@ -882,7 +888,7 @@
 	if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
 		return -XFS_ERROR(EPERM);
 
-	if (filp->f_flags & O_RDONLY)
+	if (!(filp->f_flags & FMODE_WRITE))
 		return -XFS_ERROR(EBADF);
 
 	if (vp->v_type != VREG)
diff -Nru a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c
--- a/fs/xfs/linux/xfs_iops.c	Sat Apr  3 19:38:42 2004
+++ b/fs/xfs/linux/xfs_iops.c	Sat Apr  3 19:38:42 2004
@@ -536,6 +536,10 @@
 
 	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET))
 		flags = ATTR_UTIME;
+#ifdef ATTR_NO_BLOCK
+	if ((ia_valid & ATTR_NO_BLOCK))
+		flags |= ATTR_NONBLOCK;
+#endif
 
 	VOP_SETATTR(vp, &vattr, flags, NULL, error);
 	if (error)
diff -Nru a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
--- a/fs/xfs/xfs_attr_leaf.c	Sat Apr  3 19:38:43 2004
+++ b/fs/xfs/xfs_attr_leaf.c	Sat Apr  3 19:38:43 2004
@@ -575,8 +575,8 @@
 	for ( ; i < nsbuf; i++, sbp++) {
 		attrnames_t	*namesp;
 
-		namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure :
-			((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted :
+		namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure :
+			((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted :
 			  &attr_user);
 
 		if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) {
@@ -587,8 +587,7 @@
 			ASSERT(context->flags & ATTR_KERNAMELS);
 			context->count += namesp->attr_namelen +
 						sbp->namelen + 1;
-		}
-		else {
+		} else {
 			if (xfs_attr_put_listent(context, namesp,
 					sbp->name, sbp->namelen,
 					INT_GET(sbp->valuelen, ARCH_CONVERT)))
diff -Nru a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
--- a/fs/xfs/xfs_dfrag.c	Sat Apr  3 19:38:41 2004
+++ b/fs/xfs/xfs_dfrag.c	Sat Apr  3 19:38:41 2004
@@ -119,6 +119,11 @@
 		tip = XFS_BHVTOI(tbdp);
 	}
 
+	if (ip->i_mount != tip->i_mount) {
+		error =  XFS_ERROR(EINVAL);
+		goto error0;
+	}
+
 	if (ip->i_ino == tip->i_ino) {
 		error =  XFS_ERROR(EINVAL);
 		goto error0;
@@ -147,20 +152,17 @@
 	xfs_lock_inodes(ips, 2, 0, lock_flags);
 
 	/* Check permissions */
-	if ((error = _MAC_XFS_IACCESS(ip, MACWRITE, NULL))) {
-		goto error0;
-	}
-	if ((error = _MAC_XFS_IACCESS(tip, MACWRITE, NULL))) {
+	error = xfs_iaccess(ip, S_IWUSR, NULL);
+	if (error)
 		goto error0;
-	}
-	if ((current_fsuid(cred) != ip->i_d.di_uid) &&
-	    (error = xfs_iaccess(ip, S_IWUSR, NULL)) &&
-	    !capable_cred(NULL, CAP_FOWNER)) {
+
+	error = xfs_iaccess(tip, S_IWUSR, NULL);
+	if (error)
 		goto error0;
-	}
-	if ((current_fsuid(cred) != tip->i_d.di_uid) &&
-	    (error = xfs_iaccess(tip, S_IWUSR, NULL)) &&
-	    !capable_cred(NULL, CAP_FOWNER)) {
+
+	/* Verify that both files have the same format */
+	if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
+		error = XFS_ERROR(EINVAL);
 		goto error0;
 	}
 
diff -Nru a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
--- a/fs/xfs/xfs_inode.c	Sat Apr  3 19:38:56 2004
+++ b/fs/xfs/xfs_inode.c	Sat Apr  3 19:38:56 2004
@@ -3707,14 +3707,13 @@
 	 * Read/write DACs are always overridable.
 	 * Executable DACs are overridable if at least one exec bit is set.
 	 */
-	if (!(orgmode & S_IXUSR) || (inode->i_mode & S_IXUGO) ||
-	    (ip->i_d.di_mode & S_IFMT) == S_IFDIR)
+	if (!(orgmode & S_IXUSR) ||
+	    (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
 		if (capable_cred(cr, CAP_DAC_OVERRIDE))
 			return 0;
 
 	if ((orgmode == S_IRUSR) ||
-	    (((ip->i_d.di_mode & S_IFMT) == S_IFDIR) &&
-	     (!(orgmode & ~(S_IWUSR|S_IXUSR))))) {
+	    (S_ISDIR(inode->i_mode) && (!(orgmode & S_IWUSR)))) {
 		if (capable_cred(cr, CAP_DAC_READ_SEARCH))
 			return 0;
 #ifdef	NOISE
diff -Nru a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
--- a/fs/xfs/xfs_log.c	Sat Apr  3 19:38:56 2004
+++ b/fs/xfs/xfs_log.c	Sat Apr  3 19:38:56 2004
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -940,7 +940,8 @@
 void
 xlog_iodone(xfs_buf_t *bp)
 {
-	xlog_in_core_t *iclog;
+	xlog_in_core_t	*iclog;
+	xlog_t		*l;
 	int		aborted;
 
 	iclog = XFS_BUF_FSPRIVATE(bp, xlog_in_core_t *);
@@ -949,18 +950,19 @@
 	aborted = 0;
 
 	/*
+	 * Some versions of cpp barf on the recursive definition of
+	 * ic_log -> hic_fields.ic_log and expand ic_log twice when
+	 * it is passed through two macros.  Workaround broken cpp.
+	 */
+	l = iclog->ic_log;
+
+	/*
 	 * Race to shutdown the filesystem if we see an error.
 	 */
-	if (XFS_BUF_GETERROR(bp)) {
-		/* Some versions of cpp barf on the recursive definition of
-		 * ic_log -> hic_fields.ic_log and expand ic_log twice when
-		 * it is passed through two macros.  Workaround for broken cpp
-		 */
-		struct log *l;
-		xfs_ioerror_alert("xlog_iodone",
-				  iclog->ic_log->l_mp, bp, XFS_BUF_ADDR(bp));
+	if (XFS_TEST_ERROR((XFS_BUF_GETERROR(bp)), l->l_mp,
+			XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) {
+		xfs_ioerror_alert("xlog_iodone", l->l_mp, bp, XFS_BUF_ADDR(bp));
 		XFS_BUF_STALE(bp);
-		l = iclog->ic_log;
 		xfs_force_shutdown(l->l_mp, XFS_LOG_IO_ERROR);
 		/*
 		 * This flag will be propagated to the trans-committed
@@ -3158,6 +3160,7 @@
 		uint		xflags)
 {
 	xlog_ticket_t	*tic;
+	uint		num_headers;
 	SPLDECL(s);
 
  alloc:
@@ -3181,21 +3184,30 @@
 	 * in the log.  A unit in this case is the amount of space for one
 	 * of these log operations.  Normal reservations have a cnt of 1
 	 * and their unit amount is the total amount of space required.
-	 * The following line of code adds one log record header length
-	 * for each part of an operation which may fall on a different
-	 * log record.
 	 *
-	 * One more XLOG_HEADER_SIZE is added to account for possible
-	 * round off errors when syncing a LR to disk.  The bytes are
-	 * subtracted if the thread using this ticket is the first writer
-	 * to a new LR.
-	 *
-	 * We add an extra log header for the possibility that the commit
-	 * record is the first data written to a new log record.  In this
-	 * case it is separate from the rest of the transaction data and
-	 * will be charged for the log record header.
+	 * The following lines of code account for non-transaction data
+	 * which occupy space in the on-disk log. 
 	 */
-	unit_bytes += log->l_iclog_hsize * (XLOG_BTOLRBB(unit_bytes) + 2);
+
+	/* for start-rec */
+	unit_bytes += sizeof(xlog_op_header_t); 
+
+	/* for padding */
+	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) &&
+		log->l_mp->m_sb.sb_logsunit > 1) {
+		/* log su roundoff */
+		unit_bytes += log->l_mp->m_sb.sb_logsunit;  
+	} else {
+		/* BB roundoff */
+		unit_bytes += BBSIZE;
+        }
+
+	/* for commit-rec */
+	unit_bytes += sizeof(xlog_op_header_t);
+ 
+	/* for LR headers */
+	num_headers = ((unit_bytes + log->l_iclog_size-1) >> log->l_iclog_size_log);
+	unit_bytes += log->l_iclog_hsize * num_headers;
 
 	tic->t_unit_res		= unit_bytes;
 	tic->t_curr_res		= unit_bytes;
diff -Nru a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
--- a/fs/xfs/xfs_log_priv.h	Sat Apr  3 19:38:41 2004
+++ b/fs/xfs/xfs_log_priv.h	Sat Apr  3 19:38:41 2004
@@ -57,12 +57,6 @@
 #define XLOG_RECORD_BSHIFT	14		/* 16384 == 1 << 14 */
 #define XLOG_BIG_RECORD_BSHIFT	15		/* 32k == 1 << 15 */
 #define XLOG_MAX_RECORD_BSHIFT	18		/* 256k == 1 << 18 */
-#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_BTOLRBB)
-int xlog_btolrbb(int b);
-#define XLOG_BTOLRBB(b)		xlog_btolrbb(b)
-#else
-#define XLOG_BTOLRBB(b)		(((b)+XLOG_RECORD_BSIZE-1) >> XLOG_RECORD_BSHIFT)
-#endif
 #define XLOG_BTOLSUNIT(log, b)  (((b)+(log)->l_mp->m_sb.sb_logsunit-1) / \
                                  (log)->l_mp->m_sb.sb_logsunit)
 #define XLOG_LSUNITTOB(log, su) ((su) * (log)->l_mp->m_sb.sb_logsunit)
@@ -560,6 +554,7 @@
 extern int	 xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *);
 extern xfs_caddr_t xlog_align(xlog_t *, xfs_daddr_t, int, struct xfs_buf *);
 
+/* iclog tracing */
 #define XLOG_TRACE_GRAB_FLUSH  1
 #define XLOG_TRACE_REL_FLUSH   2
 #define XLOG_TRACE_SLEEP_FLUSH 3
diff -Nru a/fs/xfs/xfs_macros.c b/fs/xfs/xfs_macros.c
--- a/fs/xfs/xfs_macros.c	Sat Apr  3 19:38:42 2004
+++ b/fs/xfs/xfs_macros.c	Sat Apr  3 19:38:42 2004
@@ -2219,14 +2219,6 @@
 }
 #endif
 
-#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_BTOLRBB)
-int
-xlog_btolrbb(int b)
-{
-	return XLOG_BTOLRBB(b);
-}
-#endif
-
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XLOG_GRANT_ADD_SPACE)
 void
 xlog_grant_add_space(xlog_t *log, int bytes, int type)
@@ -2242,3 +2234,12 @@
 	XLOG_GRANT_SUB_SPACE(log, bytes, type);
 }
 #endif
+
+#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_SB_VERSION_HASMOREBITS)
+int
+xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
+{
+	return XFS_SB_VERSION_HASMOREBITS(sbp);
+}
+#endif
+
diff -Nru a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
--- a/fs/xfs/xfs_mount.c	Sat Apr  3 19:38:42 2004
+++ b/fs/xfs/xfs_mount.c	Sat Apr  3 19:38:42 2004
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -117,6 +117,7 @@
     { offsetof(xfs_sb_t, sb_logsectlog), 0 },
     { offsetof(xfs_sb_t, sb_logsectsize),0 },
     { offsetof(xfs_sb_t, sb_logsunit),	 0 },
+    { offsetof(xfs_sb_t, sb_features2),	 0 },
     { sizeof(xfs_sb_t),			 0 }
 };
 
diff -Nru a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
--- a/fs/xfs/xfs_sb.h	Sat Apr  3 19:38:43 2004
+++ b/fs/xfs/xfs_sb.h	Sat Apr  3 19:38:43 2004
@@ -60,6 +60,7 @@
 #define XFS_SB_VERSION_SECTORBIT	0x0800
 #define	XFS_SB_VERSION_EXTFLGBIT	0x1000
 #define	XFS_SB_VERSION_DIRV2BIT		0x2000
+#define	XFS_SB_VERSION_MOREBITSBIT	0x8000
 #define	XFS_SB_VERSION_OKSASHFBITS	\
 	(XFS_SB_VERSION_EXTFLGBIT | \
 	 XFS_SB_VERSION_DIRV2BIT)
@@ -80,17 +81,46 @@
 	(XFS_SB_VERSION_NUMBITS | \
 	 XFS_SB_VERSION_OKREALFBITS | \
 	 XFS_SB_VERSION_OKSASHFBITS)
-#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2,na,sflag)	\
-	(((ia) || (dia) || (extflag) || (dirv2) || (na) || (sflag)) ? \
+#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2,na,sflag,morebits)	\
+	(((ia) || (dia) || (extflag) || (dirv2) || (na) || (sflag) || \
+	  (morebits)) ? \
 		(XFS_SB_VERSION_4 | \
 		 ((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \
 		 ((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \
 		 ((extflag) ? XFS_SB_VERSION_EXTFLGBIT : 0) | \
 		 ((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0) | \
 		 ((na) ? XFS_SB_VERSION_LOGV2BIT : 0) | \
-		 ((sflag) ? XFS_SB_VERSION_SECTORBIT : 0)) : \
+		 ((sflag) ? XFS_SB_VERSION_SECTORBIT : 0) | \
+		 ((morebits) ? XFS_SB_VERSION_MOREBITSBIT : 0)) : \
 		XFS_SB_VERSION_1)
 
+/*
+ * There are two words to hold XFS "feature" bits: the original
+ * word, sb_versionnum, and sb_features2.  Whenever a bit is set in
+ * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set.
+ *
+ * These defines represent bits in sb_features2.
+ */
+#define XFS_SB_VERSION2_REALFBITS	0x00ffffff	/* Mask: features */
+#define XFS_SB_VERSION2_RESERVED1BIT	0x00000001
+#define XFS_SB_VERSION2_SASHFBITS	0xff000000	/* Mask: features that
+							   require changing
+							   PROM and SASH */
+
+#define	XFS_SB_VERSION2_OKREALFBITS	\
+	(0)
+#define	XFS_SB_VERSION2_OKSASHFBITS	\
+	(0)
+#define XFS_SB_VERSION2_OKREALBITS	\
+	(XFS_SB_VERSION2_OKREALFBITS |	\
+	 XFS_SB_VERSION2_OKSASHFBITS )
+
+/*
+ * mkfs macro to set up sb_features2 word
+ */
+#define	XFS_SB_VERSION2_MKFS(xyz)	\
+	((xyz) ? 0 : 0)
+
 typedef struct xfs_sb
 {
 	__uint32_t	sb_magicnum;	/* magic number == XFS_SB_MAGIC */
@@ -146,6 +176,7 @@
 	__uint8_t	sb_logsectlog;	/* log2 of the log sector size */
 	__uint16_t	sb_logsectsize;	/* sector size for the log, bytes */
 	__uint32_t	sb_logsunit;	/* stripe unit size for the log */
+	__uint32_t	sb_features2;	/* additonal feature bits */
 } xfs_sb_t;
 
 /*
@@ -164,6 +195,7 @@
 	XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
 	XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
 	XFS_SBS_LOGSECTLOG, XFS_SBS_LOGSECTSIZE, XFS_SBS_LOGSUNIT,
+	XFS_SBS_FEATURES2,
 	XFS_SBS_FIELDCOUNT
 } xfs_sb_field_t;
 
@@ -217,8 +249,11 @@
 #define	XFS_SB_GOOD_VERSION_INT(sbp)	\
 	((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \
 	  ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \
-	 ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
-	  !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS)
+	   ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+	    !(((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) && \
+	      ((sbp)->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && \
+	      ((sbp)->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS))
+
 #ifdef __KERNEL__
 #define	XFS_SB_GOOD_VERSION(sbp)	\
 	(XFS_SB_GOOD_VERSION_INT(sbp) && \
@@ -452,6 +487,25 @@
 	((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
 	((sbp)->sb_versionnum & XFS_SB_VERSION_SECTORBIT))
 #endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASMOREBITSBIT)
+int xfs_sb_version_hasmorebits(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASMOREBITS(sbp)	xfs_sb_version_hasmorebits(sbp)
+#else
+#define XFS_SB_VERSION_HASMOREBITS(sbp)	\
+	((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+	 ((sbp)->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT))
+#endif
+
+/*
+ * sb_features2 bit version macros.
+ *
+ * For example, for a bit defined as XFS_SB_VERSION2_YBIT, has a macro:
+ *
+ * SB_VERSION_HASYBIT(xfs_sb_t *sbp)
+ *	((XFS_SB_VERSION_HASMOREBITS(sbp) &&
+ *	 ((sbp)->sb_versionnum & XFS_SB_VERSION2_YBIT)
+ */
 
 /*
  * end of superblock version macros
diff -Nru a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
--- a/fs/xfs/xfs_trans.c	Sat Apr  3 19:38:43 2004
+++ b/fs/xfs/xfs_trans.c	Sat Apr  3 19:38:43 2004
@@ -250,7 +250,7 @@
 		error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS,
 					  -blocks, rsvd);
 		if (error != 0) {
-                        PFLAGS_RESTORE(&tp->t_pflags);
+                        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 			return (XFS_ERROR(ENOSPC));
 		}
 		tp->t_blk_res += blocks;
@@ -323,7 +323,7 @@
 		tp->t_blk_res = 0;
 	}
 
-        PFLAGS_RESTORE(&tp->t_pflags);
+        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 
 	return (error);
 }
@@ -734,7 +734,7 @@
 			if (commit_lsn == -1 && !shutdown)
 				shutdown = XFS_ERROR(EIO);
 		}
-                PFLAGS_RESTORE(&tp->t_pflags);
+                PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 		xfs_trans_free_items(tp, shutdown? XFS_TRANS_ABORT : 0);
 		xfs_trans_free_busy(tp);
 		xfs_trans_free(tp);
@@ -823,7 +823,7 @@
 	 * had pinned, clean up, free trans structure, and return error.
 	 */
 	if (error || commit_lsn == -1) {
-                PFLAGS_RESTORE(&tp->t_pflags);
+                PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 		xfs_trans_uncommit(tp, flags|XFS_TRANS_ABORT);
 		return XFS_ERROR(EIO);
 	}
@@ -862,7 +862,7 @@
 	error = xfs_log_notify(mp, commit_iclog, &(tp->t_logcb));
 
 	/* mark this thread as no longer being in a transaction */
-        PFLAGS_RESTORE(&tp->t_pflags);
+        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 
 	/*
 	 * Once all the items of the transaction have been copied
@@ -1100,7 +1100,7 @@
 	}
 
 	/* mark this thread as no longer being in a transaction */
-        PFLAGS_RESTORE(&tp->t_pflags);
+        PFLAGS_RESTORE_FSTRANS(&tp->t_pflags);
 
 	xfs_trans_free_items(tp, flags);
 	xfs_trans_free_busy(tp);
diff -Nru a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
--- a/fs/xfs/xfs_trans.h	Sat Apr  3 19:38:54 2004
+++ b/fs/xfs/xfs_trans.h	Sat Apr  3 19:38:54 2004
@@ -535,6 +535,8 @@
  *    the super block to reflect the freed blocks: sector size
  *    worst case split in allocation btrees per extent assuming 4 extents:
  *		4 exts * 2 trees * (2 * max depth - 1) * block size
+ *    the inode btree: max depth * blocksize
+ *    the allocation btrees: 2 trees * (max depth - 1) * block size
  */
 #define	XFS_CALC_ITRUNCATE_LOG_RES(mp) \
 	(MAX( \
@@ -545,7 +547,11 @@
 	  (4 * (mp)->m_sb.sb_sectsize) + \
 	  (mp)->m_sb.sb_sectsize + \
 	  XFS_ALLOCFREE_LOG_RES(mp, 4) + \
-	  (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4))))))
+	  (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4))) + \
+	  (128 * 5) + \
+	  XFS_ALLOCFREE_LOG_RES(mp, 1) + \
+	   (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \
+	    XFS_ALLOCFREE_LOG_COUNT(mp, 1))))))
 
 #define	XFS_ITRUNCATE_LOG_RES(mp)   ((mp)->m_reservations.tr_itruncate)
 
@@ -713,6 +719,7 @@
 	 XFS_FSB_TO_B((mp), 1) + \
 	 MAX((__uint16_t)XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \
 	 (128 * 5) + \
+	  XFS_ALLOCFREE_LOG_RES(mp, 1) + \
 	  (128 * (2 + XFS_IALLOC_BLOCKS(mp) + XFS_IN_MAXLEVELS(mp) + \
 	   XFS_ALLOCFREE_LOG_COUNT(mp, 1))))
 
diff -Nru a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
--- a/fs/xfs/xfs_vfsops.c	Sat Apr  3 19:38:41 2004
+++ b/fs/xfs/xfs_vfsops.c	Sat Apr  3 19:38:41 2004
@@ -1,7 +1,7 @@
 /*
  * XFS filesystem operations.
  *
- * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -229,7 +229,10 @@
 		mp->m_swidth = ap->swidth;
 	}
 
-	if (ap->logbufs != 0 && ap->logbufs != -1 &&
+	if (ap->logbufs != -1 &&
+#if defined(DEBUG) || defined(XLOG_NOLOG)
+	    ap->logbufs != 0 &&
+#endif
 	    (ap->logbufs < XLOG_MIN_ICLOGS ||
 	     ap->logbufs > XLOG_MAX_ICLOGS)) {
 		cmn_err(CE_WARN,
@@ -1484,8 +1487,10 @@
 			 */
 			if (XFS_BUF_ISPINNED(bp))
 				xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
-			if (!(flags & SYNC_WAIT))
-				XFS_BUF_BFLAGS(bp) |= XFS_B_ASYNC;
+			if (flags & SYNC_WAIT)
+				XFS_BUF_UNASYNC(bp);
+			else
+				XFS_BUF_ASYNC(bp);
 			error = xfs_bwrite(mp, bp);
 		}
 		if (error) {
diff -Nru a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
--- a/fs/xfs/xfs_vnodeops.c	Sat Apr  3 19:38:57 2004
+++ b/fs/xfs/xfs_vnodeops.c	Sat Apr  3 19:38:57 2004
@@ -1106,14 +1106,11 @@
 	xfs_off_t	stop)
 {
 	xfs_inode_t	*ip;
-	int		error;
-	int		error2;
-	int		syncall;
-	vnode_t		*vp;
 	xfs_trans_t	*tp;
+	int		error;
 
-	vp = BHV_TO_VNODE(bdp);
-	vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
+	vn_trace_entry(BHV_TO_VNODE(bdp),
+			__FUNCTION__, (inst_t *)__return_address);
 
 	ip = XFS_BHVTOI(bdp);
 
@@ -1122,44 +1119,6 @@
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return XFS_ERROR(EIO);
 
-	xfs_ilock(ip, XFS_IOLOCK_EXCL);
-
-	syncall = error = error2 = 0;
-
-	if (stop == -1)  {
-		ASSERT(start >= 0);
-		if (start == 0)
-			syncall = 1;
-		stop = xfs_file_last_byte(ip);
-	}
-
-	/*
-	 * If we're invalidating, always flush since we want to
-	 * tear things down.  Otherwise, don't flush anything if
-	 * we're not dirty.
-	 */
-	if (flag & FSYNC_INVAL) {
-		if (ip->i_df.if_flags & XFS_IFEXTENTS &&
-		    ip->i_df.if_bytes > 0) {
-			VOP_FLUSHINVAL_PAGES(vp, start, -1, FI_REMAPF_LOCKED);
-		}
-		ASSERT(syncall == 0 || (VN_CACHED(vp) == 0));
-	} else {
-		/*
-		 * In the non-invalidating case, calls to fsync() do not
-		 * flush all the dirty mmap'd pages.  That requires a
-		 * call to msync().
-		 */
-		VOP_FLUSH_PAGES(vp, start, -1,
-				(flag & FSYNC_WAIT) ? 0 : XFS_B_ASYNC,
-				FI_NONE, error2);
-	}
-
-	if (error2) {
-		xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-		return XFS_ERROR(error2);
-	}
-
 	/*
 	 * We always need to make sure that the required inode state
 	 * is safe on disk.  The vnode might be clean but because
@@ -1199,7 +1158,7 @@
 		 * be pinned.  If it is, force the log.
 		 */
 
-		xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED);
+		xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
 		if (xfs_ipincount(ip)) {
 			xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
@@ -1222,7 +1181,6 @@
 				XFS_FSYNC_TS_LOG_RES(ip->i_mount),
 				0, 0, 0)))  {
 			xfs_trans_cancel(tp, 0);
-			xfs_iunlock(ip, XFS_IOLOCK_EXCL);
 			return error;
 		}
 		xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -1237,67 +1195,17 @@
 		 * inode in another recent transaction.	 So we
 		 * play it safe and fire off the transaction anyway.
 		 */
-		xfs_trans_ijoin(tp, ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL);
+		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
 		xfs_trans_ihold(tp, ip);
 		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 		if (flag & FSYNC_WAIT)
 			xfs_trans_set_sync(tp);
 		error = xfs_trans_commit(tp, 0, NULL);
 
-		xfs_iunlock(ip, XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL);
+		xfs_iunlock(ip, XFS_ILOCK_EXCL);
 	}
 	return error;
 }
-
-
-#if 0
-/*
- * This is a utility routine for xfs_inactive.  It is called when a
- * transaction attempting to free up the disk space for a file encounters
- * an error.  It cancels the old transaction and starts up a new one
- * to be used to free up the inode.  It also sets the inode size and extent
- * counts to 0 and frees up any memory being used to store inline data,
- * extents, or btree roots.
- */
-STATIC void
-xfs_itruncate_cleanup(
-	xfs_trans_t	**tpp,
-	xfs_inode_t	*ip,
-	int		commit_flags,
-	int		fork)
-{
-	xfs_mount_t	*mp;
-	/* REFERENCED */
-	int		error;
-
-	mp = ip->i_mount;
-	if (*tpp) {
-		xfs_trans_cancel(*tpp, commit_flags | XFS_TRANS_ABORT);
-	}
-	xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-	*tpp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
-	error = xfs_trans_reserve(*tpp, 0, XFS_IFREE_LOG_RES(mp), 0, 0,
-				  XFS_DEFAULT_LOG_COUNT);
-	if (error) {
-		return;
-	}
-
-	xfs_ilock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-	xfs_trans_ijoin(*tpp, ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
-	xfs_trans_ihold(*tpp, ip);
-
-	xfs_idestroy_fork(ip, fork);
-
-	if (fork == XFS_DATA_FORK) {
-		ip->i_d.di_nblocks = 0;
-		ip->i_d.di_nextents = 0;
-		ip->i_d.di_size = 0;
-	} else {
-		ip->i_d.di_anextents = 0;
-	}
-	xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE);
-}
-#endif
 
 /*
  * This is called by xfs_inactive to free any blocks beyond eof,
diff -Nru a/include/acpi/acconfig.h b/include/acpi/acconfig.h
--- a/include/acpi/acconfig.h	Sat Apr  3 19:38:54 2004
+++ b/include/acpi/acconfig.h	Sat Apr  3 19:38:54 2004
@@ -64,7 +64,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20040220
+#define ACPI_CA_VERSION                 0x20040326
 
 /* Maximum objects in the various object caches */
 
@@ -184,6 +184,10 @@
 /* SMBus bidirectional buffer size */
 
 #define ACPI_SMBUS_BUFFER_SIZE          34
+
+/* Number of strings associated with the _OSI reserved method */
+
+#define ACPI_NUM_OSI_STRINGS            4
 
 
 /******************************************************************************
diff -Nru a/include/acpi/acglobal.h b/include/acpi/acglobal.h
--- a/include/acpi/acglobal.h	Sat Apr  3 19:38:40 2004
+++ b/include/acpi/acglobal.h	Sat Apr  3 19:38:40 2004
@@ -79,6 +79,15 @@
 
 extern      u32                                 acpi_gbl_nesting_level;
 
+/*****************************************************************************
+ *
+ * Runtime configuration
+ *
+ ****************************************************************************/
+
+ACPI_EXTERN u8                                  acpi_gbl_create_osi_method;
+ACPI_EXTERN u8                                  acpi_gbl_all_methods_serialized;
+ACPI_EXTERN u8                                  acpi_gbl_leave_wake_gpes_disabled;
 
 /*****************************************************************************
  *
@@ -169,6 +178,7 @@
 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 +189,7 @@
 
 #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
@@ -187,6 +197,7 @@
 
 ACPI_EXTERN struct acpi_namespace_node          acpi_gbl_root_node_struct;
 ACPI_EXTERN struct acpi_namespace_node         *acpi_gbl_root_node;
+ACPI_EXTERN struct acpi_namespace_node         *acpi_gbl_fadt_gpe_device;
 
 extern const u8                                 acpi_gbl_ns_properties[NUM_NS_TYPES];
 extern const struct acpi_predefined_names       acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES];
diff -Nru a/include/acpi/achware.h b/include/acpi/achware.h
--- a/include/acpi/achware.h	Sat Apr  3 19:38:44 2004
+++ b/include/acpi/achware.h	Sat Apr  3 19:38:44 2004
@@ -149,11 +149,11 @@
 	acpi_event_status               *event_status);
 
 acpi_status
-acpi_hw_disable_non_wakeup_gpes (
+acpi_hw_prepare_gpes_for_sleep (
 	void);
 
 acpi_status
-acpi_hw_enable_non_wakeup_gpes (
+acpi_hw_restore_gpes_on_wake (
 	void);
 
 
diff -Nru a/include/acpi/aclocal.h b/include/acpi/aclocal.h
--- a/include/acpi/aclocal.h	Sat Apr  3 19:38:44 2004
+++ b/include/acpi/aclocal.h	Sat Apr  3 19:38:44 2004
@@ -360,6 +360,13 @@
 };
 
 
+struct acpi_gpe_walk_info
+{
+	struct acpi_namespace_node              *gpe_device;
+	struct acpi_gpe_block_info              *gpe_block;
+};
+
+
 typedef acpi_status (*ACPI_GPE_CALLBACK) (
 	struct acpi_gpe_xrupt_info      *gpe_xrupt_info,
 	struct acpi_gpe_block_info      *gpe_block);
diff -Nru a/include/acpi/acmacros.h b/include/acpi/acmacros.h
--- a/include/acpi/acmacros.h	Sat Apr  3 19:38:43 2004
+++ b/include/acpi/acmacros.h	Sat Apr  3 19:38:43 2004
@@ -681,7 +681,4 @@
 
 #endif /* ACPI_DBG_TRACK_ALLOCATIONS */
 
-
-#define ACPI_GET_STACK_POINTER          _asm {mov eax, ebx}
-
 #endif /* ACMACROS_H */
diff -Nru a/include/acpi/acobject.h b/include/acpi/acobject.h
--- a/include/acpi/acobject.h	Sat Apr  3 19:38:41 2004
+++ b/include/acpi/acobject.h	Sat Apr  3 19:38:41 2004
@@ -180,7 +180,11 @@
 };
 
 
-#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 @@
 	u32                                     aml_length;
 	void                                    *semaphore;
 	u8                                      *aml_start;
+	ACPI_INTERNAL_METHOD            implementation;
 	u8                                      concurrency;
 	u8                                      thread_count;
 	acpi_owner_id                           owning_id;
diff -Nru a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
--- a/include/acpi/acpi_bus.h	Sat Apr  3 19:38:57 2004
+++ b/include/acpi/acpi_bus.h	Sat Apr  3 19:38:57 2004
@@ -32,8 +32,6 @@
 
 #define PREFIX			"ACPI: "
 
-extern int			acpi_disabled;
-
 /* TBD: Make dynamic */
 #define ACPI_MAX_HANDLES	10
 struct acpi_handle_list {
diff -Nru a/include/acpi/acpixf.h b/include/acpi/acpixf.h
--- a/include/acpi/acpixf.h	Sat Apr  3 19:38:40 2004
+++ b/include/acpi/acpixf.h	Sat Apr  3 19:38:40 2004
@@ -450,7 +450,7 @@
 acpi_enter_sleep_state (
 	u8                              sleep_state);
 
-acpi_status
+acpi_status asmlinkage
 acpi_enter_sleep_state_s4bios (
 	void);
 
diff -Nru a/include/acpi/actypes.h b/include/acpi/actypes.h
--- a/include/acpi/actypes.h	Sat Apr  3 19:38:44 2004
+++ b/include/acpi/actypes.h	Sat Apr  3 19:38:44 2004
@@ -349,7 +349,6 @@
 /*
  * Power state values
  */
-
 #define ACPI_STATE_UNKNOWN              (u8) 0xFF
 
 #define ACPI_STATE_S0                   (u8) 0
@@ -393,7 +392,6 @@
 #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,14 +407,13 @@
 #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
  * of the ACPI object_type() operator (See the ACPI Spec). Therefore,
  * only add to the first group if the spec changes.
  *
- * Types must be kept in sync with the global acpi_ns_properties
+ * NOTE: Types must be kept in sync with the global acpi_ns_properties
  * and acpi_ns_type_names arrays.
  */
 typedef u32                                     acpi_object_type;
@@ -453,26 +450,27 @@
 #define ACPI_TYPE_LOCAL_INDEX_FIELD     0x13
 #define ACPI_TYPE_LOCAL_REFERENCE       0x14  /* Arg#, Local#, Name, Debug, ref_of, Index */
 #define ACPI_TYPE_LOCAL_ALIAS           0x15
-#define ACPI_TYPE_LOCAL_NOTIFY          0x16
-#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x17
-#define ACPI_TYPE_LOCAL_RESOURCE        0x18
-#define ACPI_TYPE_LOCAL_RESOURCE_FIELD  0x19
-#define ACPI_TYPE_LOCAL_SCOPE           0x1A  /* 1 Name, multiple object_list Nodes */
+#define ACPI_TYPE_LOCAL_METHOD_ALIAS    0x16
+#define ACPI_TYPE_LOCAL_NOTIFY          0x17
+#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x18
+#define ACPI_TYPE_LOCAL_RESOURCE        0x19
+#define ACPI_TYPE_LOCAL_RESOURCE_FIELD  0x1A
+#define ACPI_TYPE_LOCAL_SCOPE           0x1B  /* 1 Name, multiple object_list Nodes */
 
-#define ACPI_TYPE_NS_NODE_MAX           0x1A  /* Last typecode used within a NS Node */
+#define ACPI_TYPE_NS_NODE_MAX           0x1B  /* Last typecode used within a NS Node */
 
 /*
  * These are special object types that never appear in
  * a Namespace node, only in an union acpi_operand_object
  */
-#define ACPI_TYPE_LOCAL_EXTRA           0x1B
-#define ACPI_TYPE_LOCAL_DATA            0x1C
+#define ACPI_TYPE_LOCAL_EXTRA           0x1C
+#define ACPI_TYPE_LOCAL_DATA            0x1D
 
-#define ACPI_TYPE_LOCAL_MAX             0x1C
+#define ACPI_TYPE_LOCAL_MAX             0x1D
 
 /* All types above here are invalid */
 
-#define ACPI_TYPE_INVALID               0x1D
+#define ACPI_TYPE_INVALID               0x1E
 #define ACPI_TYPE_NOT_FOUND             0xFF
 
 
@@ -514,9 +512,8 @@
 #define ACPI_WRITE                      1
 #define ACPI_IO_MASK                    1
 
-
 /*
- * Acpi Event Types: Fixed & General Purpose
+ * Event Types: Fixed & General Purpose
  */
 typedef u32                                     acpi_event_type;
 
@@ -531,25 +528,8 @@
 #define ACPI_EVENT_MAX                  4
 #define ACPI_NUM_FIXED_EVENTS           ACPI_EVENT_MAX + 1
 
-#define ACPI_GPE_INVALID                0xFF
-#define ACPI_GPE_MAX                    0xFF
-#define ACPI_NUM_GPE                    256
-
-#define ACPI_EVENT_LEVEL_TRIGGERED      1
-#define ACPI_EVENT_EDGE_TRIGGERED       2
-
-/*
- * Flags for GPE and Lock interfaces
- */
-#define ACPI_EVENT_WAKE_ENABLE          0x2
-#define ACPI_EVENT_WAKE_DISABLE         0x2
-
-#define ACPI_NOT_ISR                    0x1
-#define ACPI_ISR                        0x0
-
-
 /*
- * acpi_event Status:
+ * Event Status - Per event
  * -------------
  * The encoding of acpi_event_status is illustrated below.
  * Note that a set bit (1) indicates the property is TRUE
@@ -570,6 +550,45 @@
 #define ACPI_EVENT_FLAG_WAKE_ENABLED    (acpi_event_status) 0x02
 #define ACPI_EVENT_FLAG_SET             (acpi_event_status) 0x04
 
+/*
+ * General Purpose Events (GPE)
+ */
+#define ACPI_GPE_INVALID                0xFF
+#define ACPI_GPE_MAX                    0xFF
+#define ACPI_NUM_GPE                    256
+
+/*
+ * GPE info flags - Per GPE
+ * +---------+-+-+-+
+ * |Bits 8:3 |2|1|0|
+ * +---------+-+-+-+
+ *          | | | |
+ *          | | | +- Edge or Level Triggered
+ *          | | +--- Type: Wake or Runtime
+ *          | +----- Enabled for wake?
+ *          +--------<Reserved>
+ */
+#define ACPI_GPE_XRUPT_TYPE_MASK        (u8) 1
+#define ACPI_GPE_LEVEL_TRIGGERED        (u8) 1
+#define ACPI_GPE_EDGE_TRIGGERED         (u8) 0
+
+#define ACPI_GPE_TYPE_MASK              (u8) 2
+#define ACPI_GPE_TYPE_WAKE              (u8) 2
+#define ACPI_GPE_TYPE_RUNTIME           (u8) 0       /* Default */
+
+#define ACPI_GPE_ENABLE_MASK            (u8) 4
+#define ACPI_GPE_ENABLED                (u8) 4
+#define ACPI_GPE_DISABLED               (u8) 0       /* Default */
+
+/*
+ * Flags for GPE and Lock interfaces
+ */
+#define ACPI_EVENT_WAKE_ENABLE          0x2
+#define ACPI_EVENT_WAKE_DISABLE         0x2
+
+#define ACPI_NOT_ISR                    0x1
+#define ACPI_ISR                        0x0
+
 
 /* Notify types */
 
@@ -794,7 +813,7 @@
 #define ACPI_INIT_DEVICE_INI        1
 
 
-/* Address Spaces (Operation Regions */
+/* Address Spaces (For Operation Regions) */
 
 typedef
 acpi_status (*acpi_adr_space_handler) (
diff -Nru a/include/acpi/acutils.h b/include/acpi/acutils.h
--- a/include/acpi/acutils.h	Sat Apr  3 19:38:40 2004
+++ b/include/acpi/acutils.h	Sat Apr  3 19:38:40 2004
@@ -52,7 +52,6 @@
 	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_pkg_callback               walk_callback,
 	void                            *context);
 
-
 struct acpi_pkg_info
 {
 	u8                              *free_space;
@@ -473,7 +471,12 @@
 #define METHOD_NAME__PRT        "_PRT"
 #define METHOD_NAME__CRS        "_CRS"
 #define METHOD_NAME__PRS        "_PRS"
+#define METHOD_NAME__PRW        "_PRW"
+
 
+acpi_status
+acpi_ut_osi_implementation (
+	struct acpi_walk_state          *walk_state);
 
 acpi_status
 acpi_ut_evaluate_object (
diff -Nru a/include/acpi/amlcode.h b/include/acpi/amlcode.h
--- a/include/acpi/amlcode.h	Sat Apr  3 19:38:45 2004
+++ b/include/acpi/amlcode.h	Sat Apr  3 19:38:45 2004
@@ -496,11 +496,17 @@
 } 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 -Nru a/include/asm-alpha/elf.h b/include/asm-alpha/elf.h
--- a/include/asm-alpha/elf.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-alpha/elf.h	Sat Apr  3 19:38:43 2004
@@ -137,10 +137,44 @@
 	: amask (AMASK_CIX) ? "ev6" : "ev67");	\
 })
 
+/* Reserve these numbers for any future use of a VDSO.  */
+#if 0
+#define AT_SYSINFO		32
+#define AT_SYSINFO_EHDR		33
+#endif
+
+/* More complete cache descriptions than AT_[DIU]CACHEBSIZE.  If the
+   value is -1, then the cache doesn't exist.  Otherwise:
+
+      bit 0-3:	  Cache set-associativity; 0 means fully associative.
+      bit 4-7:	  Log2 of cacheline size.
+      bit 8-31:	  Size of the entire cache >> 8.
+      bit 32-63:  Reserved.
+*/
+
+#define AT_L1I_CACHESHAPE	34
+#define AT_L1D_CACHESHAPE	35
+#define AT_L2_CACHESHAPE	36
+#define AT_L3_CACHESHAPE	37
+
 #ifdef __KERNEL__
+
 #define SET_PERSONALITY(EX, IBCS2)				\
 	set_personality(((EX).e_flags & EF_ALPHA_32BIT)		\
 	   ? PER_LINUX_32BIT : (IBCS2) ? PER_SVR4 : PER_LINUX)
-#endif
 
-#endif
+extern int alpha_l1i_cacheshape;
+extern int alpha_l1d_cacheshape;
+extern int alpha_l2_cacheshape;
+extern int alpha_l3_cacheshape;
+
+#define ARCH_DLINFO						\
+  do {								\
+    NEW_AUX_ENT(AT_L1I_CACHESHAPE, alpha_l1i_cacheshape);	\
+    NEW_AUX_ENT(AT_L1D_CACHESHAPE, alpha_l1d_cacheshape);	\
+    NEW_AUX_ENT(AT_L2_CACHESHAPE, alpha_l2_cacheshape);		\
+    NEW_AUX_ENT(AT_L3_CACHESHAPE, alpha_l3_cacheshape);		\
+  } while (0)
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_ALPHA_ELF_H */
diff -Nru a/include/asm-alpha/module.h b/include/asm-alpha/module.h
--- a/include/asm-alpha/module.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-alpha/module.h	Sat Apr  3 19:38:41 2004
@@ -17,7 +17,7 @@
 #define ARCH_SHF_SMALL SHF_ALPHA_GPREL
 
 #ifdef MODULE
-asm(".section .got,\"aws\",@nobits; .align 3; .previous");
+asm(".section .got,\"aws\",@progbits; .align 3; .previous");
 #endif
 
 #endif /*_ALPHA_MODULE_H*/
diff -Nru a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
--- a/include/asm-alpha/pci.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-alpha/pci.h	Sat Apr  3 19:38:40 2004
@@ -85,10 +85,10 @@
 
 extern void pci_free_consistent(struct pci_dev *, size_t, void *, dma_addr_t);
 
-/* 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.  */
+/* 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_for_cpu is performed.  */
 
 extern dma_addr_t pci_map_single(struct pci_dev *, void *, size_t, int);
 
@@ -96,6 +96,14 @@
 extern dma_addr_t pci_map_page(struct pci_dev *, struct page *,
 			       unsigned long, size_t, int);
 
+/* Test for pci_map_single or pci_map_page having generated an error.  */
+
+static inline int
+pci_dma_mapping_error(dma_addr_t dma_addr)
+{
+	return dma_addr == 0;
+}
+
 /* Unmap a single streaming mode DMA translation.  The DMA_ADDR and
    SIZE must match what was provided for in a previous pci_map_single
    call.  All other usages are undefined.  After this call, reads by
@@ -142,28 +150,44 @@
 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(struct pci_dev *dev, struct scatterlist *sg, int nents,
-	        int direction)
+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_for_device(struct pci_dev *dev, struct scatterlist *sg,
+			   int nents, int direction)
 {
 	/* Nothing to do.  */
 }
@@ -180,23 +204,32 @@
 extern int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask);
 
 /* Convert to/from DAC dma address and struct page.  */
-extern dma64_addr_t pci_dac_page_to_dma(struct pci_dev *, struct page *, unsigned long, int);
+extern dma64_addr_t pci_dac_page_to_dma(struct pci_dev *, struct page *,
+					unsigned long, int);
 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. */
 }
 
-extern void
-pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
-			 struct resource *res);
+extern void pcibios_resource_to_bus(struct pci_dev *, struct pci_bus_region *,
+				    struct resource *);
 
 #define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
 
-static inline int pci_name_bus(char *name, struct pci_bus *bus)
+static inline int
+pci_name_bus(char *name, struct pci_bus *bus)
 {
 	struct pci_controller *hose = bus->sysdata;
 
@@ -208,7 +241,8 @@
 	return 0;
 }
 
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+static inline void
+pcibios_add_platform_entries(struct pci_dev *dev)
 {
 }
 
diff -Nru a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
--- a/include/asm-alpha/unistd.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-alpha/unistd.h	Sat Apr  3 19:38:43 2004
@@ -616,16 +616,16 @@
 
 #endif /* __KERNEL_SYSCALLS__ */
 
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand.
- *
- * Note that we do *not* provide a parameter list to avoid 
- * conflicting with one of the syscall declarations in some
- * of the relevant header files (including this one).
- */
-#define cond_syscall(x) asmlinkage long x() __attribute__((weak,alias("sys_ni_syscall")));
+/* "Conditional" syscalls.  What we want is
+
+	__attribute__((weak,alias("sys_ni_syscall")))
+
+   but that raises the problem of what type to give the symbol.  If we use
+   a prototype, it'll conflict with the definition given in this file and
+   others.  If we use __typeof, we discover that not all symbols actually
+   have declarations.  If we use no prototype, then we get warnings from
+   -Wstrict-prototypes.  Ho hum.  */
+
+#define cond_syscall(x)  asm(".weak\t" #x "\n" #x " = sys_ni_syscall");
 
 #endif /* _ALPHA_UNISTD_H */
diff -Nru a/include/asm-arm/arch-anakin/dma.h b/include/asm-arm/arch-anakin/dma.h
--- a/include/asm-arm/arch-anakin/dma.h	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/dma.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   09-Apr-2001 W/TTC	Created
- */
-
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-#define MAX_DMA_ADDRESS		0xffffffff
-#define MAX_DMA_CHANNELS	0
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/hardware.h b/include/asm-arm/arch-anakin/hardware.h
--- a/include/asm-arm/arch-anakin/hardware.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/hardware.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   10-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * Memory map
- */
-#define SRAM_START		0x00000000
-#define SRAM_SIZE		0x00100000
-#define SRAM_BASE		0xdf000000
-
-#define SDRAM_START		0x20000000
-#define SDRAM_SIZE		0x04000000
-#define SDRAM_BASE		0xc0000000
-
-#define IO_START		0x40000000
-#define IO_SIZE			0x00100000
-#define IO_BASE			0xe0000000
-
-#define FLASH_START		0x60000000
-#define FLASH_SIZE		0x00080000
-#define FLASH_BASE		0xe8000000
-
-#define VGA_START		0x80000000
-#define VGA_SIZE		0x0002db40
-#define VGA_BASE		0xf0000000
-
-/*
- * IO map
- */
-#define IO_CONTROLLER		0x00000
-#define INTERRUPT_CONTROLLER	0x02000
-#define UART0			0x04000
-#define UART1			0x06000
-#define UART2			0x08000
-#define CODEC			0x0a000
-#define UART4			0x0c000
-#define UART3			0x0e000
-#define DISPLAY_CONTROLLER	0x10000
-#define DAB			0x12000
-#define STATE_CONTROLLER	0x14000
-#define CAN			0x23000
-#define COMPACTFLASH		0x24000
-
-/*
- * Use SRAM for D-cache flush
- */
-#define FLUSH_BASE_PHYS		SRAM_START
-#define FLUSH_BASE		SRAM_BASE
-#define UNCACHEABLE_ADDR	(SRAM_BASE + 0x10000)
-
-/*
- * Use SDRAM for memory
- */
-#define MEM_SIZE		SDRAM_SIZE
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/ide.h b/include/asm-arm/arch-anakin/ide.h
--- a/include/asm-arm/arch-anakin/ide.h	Sat Apr  3 19:38:40 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-/*
- * linux/include/asm-arm/arch-anakin/ide.h
- *
- * Copyright 2001 Blue Mug Inc. for Acunia N.V.
- *
- * 08-jun-2001: Initial clone of arch-sa1100/ide.h by Jon McClintock
- *              (jonm@bluemug.com).
- */
- 
-#include <asm/irq.h>
-#include <asm/hardware.h>
-
-/*
- * Set up a hw structure for a specified data port, control port and IRQ.
- * This should follow whatever the default interface uses.
- */
-static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
-{
-	ide_ioreg_t reg;
-	int i;
-	int regincr = 4;
-	
-	memset(hw, 0, sizeof(*hw));
-
-	reg = (ide_ioreg_t)data_port;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += regincr;
-	}
-
-	hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-
-	if (irq)
-		*irq = 0;
-}
-
-
-/*
- * This registers the standard ports for this architecture with the IDE
- * driver.
- */
-static __inline__ void
-ide_init_default_hwifs(void)
-{
-    hw_regs_t hw;
-
-    ide_init_hwif_ports(&hw, IO_BASE + COMPACTFLASH,
-			IO_BASE + COMPACTFLASH + IDE_CONTROL_OFFSET, NULL);
-    hw.irq = IRQ_COMPACTFLASH;
-    ide_register_hw(&hw);
-}
-
-
diff -Nru a/include/asm-arm/arch-anakin/io.h b/include/asm-arm/arch-anakin/io.h
--- a/include/asm-arm/arch-anakin/io.h	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/io.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   10-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-
-#define IO_SPACE_LIMIT		0xffffffff
-
-#define __io(a)			(a)
-
-/*
- * We don't support ins[lb]/outs[lb].  Make them fault.
- */
-#define __raw_readsb(p,d,l)	do { *(int *)0 = 0; } while (0)
-#define __raw_readsl(p,d,l)	do { *(int *)0 = 0; } while (0)
-#define __raw_writesb(p,d,l)	do { *(int *)0 = 0; } while (0)
-#define __raw_writesl(p,d,l)	do { *(int *)0 = 0; } while (0)
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/irqs.h b/include/asm-arm/arch-anakin/irqs.h
--- a/include/asm-arm/arch-anakin/irqs.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,33 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/irqs.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   10-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_IRQS_H
-#define __ASM_ARCH_IRQS_H
-
-#define NR_IRQS			16
-
-#define IRQ_UART0		0
-#define IRQ_UART1		1
-#define IRQ_UART2		2
-#define IRQ_TICK		3
-#define IRQ_CODEC		4
-#define IRQ_UART4		5
-#define IRQ_TOUCHSCREEN		6
-#define IRQ_UART3		7
-#define IRQ_FIFO		8
-#define IRQ_CAN			9
-#define IRQ_COMPACTFLASH	10
-#define IRQ_BOSH		12
-#define IRQ_ANAKIN		15
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/memory.h b/include/asm-arm/arch-anakin/memory.h
--- a/include/asm-arm/arch-anakin/memory.h	Sat Apr  3 19:38:56 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/memory.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   09-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#define TASK_SIZE		(0xbf000000)
-#define TASK_SIZE_26		(64u * 1024 * 1024)
-#define TASK_UNMAPPED_BASE	(0x40000000)
-
-#define PAGE_OFFSET		0xc0000000
-#define PHYS_OFFSET		0x20000000
-
-#define __virt_to_phys(a)	((a) - PAGE_OFFSET + PHYS_OFFSET)
-#define __phys_to_virt(a)	((a) + PAGE_OFFSET - PHYS_OFFSET)
-#define __virt_to_bus(a)	__virt_to_phys(a)
-#define __bus_to_virt(a)	__phys_to_virt(a)
-
-#define __virt_to_phys__is_a_macro
-#define __phys_to_virt__is_a_macro
-#define __virt_to_bus__is_a_macro
-#define __bus_to_virt__is_a_macro
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/param.h b/include/asm-arm/arch-anakin/param.h
--- a/include/asm-arm/arch-anakin/param.h	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,16 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/param.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   11-Apr-2001 TTC	Created
- */
-
-/*
- * Reserved for future use
- */
diff -Nru a/include/asm-arm/arch-anakin/serial.h b/include/asm-arm/arch-anakin/serial.h
--- a/include/asm-arm/arch-anakin/serial.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,29 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/serial.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   11-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-/*
- * UART3 and UART4 are not supported yet
- */
-#define STD_SERIAL_PORT_DEFNS	\
-	{ 0, 0, IO_BASE + UART0, IRQ_UART0, 0 }, \
-	{ 0, 0, IO_BASE + UART1, IRQ_UART1, 0 }, \
-	{ 0, 0, IO_BASE + UART2, IRQ_UART2, 0 }
-#define EXTRA_SERIAL_PORT_DEFNS
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/serial_reg.h b/include/asm-arm/arch-anakin/serial_reg.h
--- a/include/asm-arm/arch-anakin/serial_reg.h	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,65 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/serial_reg.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   09-Apr-2001 TTC	Created
- */
-
-#ifndef ASM_ARCH_SERIAL_REG_H
-#define ASM_ARCH_SERIAL_REG_H
-
-/*
- * Serial registers (other than tx/rx)
- */
-
-/*
- * [UARTx + 0x10]
- */
-#define RXRELEASE		(1 << 0)
-#define TXEMPTY			(1 << 1)
-#define CTS			(1 << 2)
-#define PRESCALER		(31 << 3)
-#define SETBAUD(baud)		((230400 / (baud) - 1) << 3)
-#define GETBAUD(prescaler)	(230400 / (((prescaler) >> 3) + 1))
-
-
-/*
- * [UARTx + 0x18]
- */
-#define IRQENABLE		(1 << 0)
-#define SENDREQUEST		(1 << 1)
-#define RTS			(1 << 2)
-#define DTR			(1 << 3)
-#define DCD			(1 << 4)
-#define BLOCKRX			(1 << 5)
-#define PARITY			(3 << 6)
-#define SETPARITY(parity)	((parity) << 6)
-#define GETPARITY(parity)	((parity) >> 6)
-#define NONEPARITY              (0)
-#define ODDPARITY               (1)
-#define EVENPARITY              (2)
-
-/*
- * [UARTx + 0x1c]
- */
-#define TX			(1 << 0)
-#define RX			(1 << 1)
-#define OVERRUN			(1 << 2)
-
-/*
- * [UARTx + 0x20]
- */
-#define SETBREAK		(1 << 0)
-
-/*
- * Software interrupt register
- */
-#define TXENABLE		(1 << 0)
-
-#endif 
diff -Nru a/include/asm-arm/arch-anakin/system.h b/include/asm-arm/arch-anakin/system.h
--- a/include/asm-arm/arch-anakin/system.h	Sat Apr  3 19:38:45 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/system.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   11-Apr-2001 TTC	Created
- *   04-May-2001 W/PB	Removed cpu_do_idle()
- */
-
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-static inline void arch_idle(void)
-{
-}
-
-static inline void
-arch_reset(char mode)
-{
-	cpu_reset(0);
-}
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/time.h b/include/asm-arm/arch-anakin/time.h
--- a/include/asm-arm/arch-anakin/time.h	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/time.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   10-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_TIME_H
-#define __ASM_ARCH_TIME_H
-
-static irqreturn_t
-anakin_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	do_timer(regs);
-	return IRQ_HANDLED;
-}
-
-void __init time_init(void)
-{
-	timer_irq.handler = anakin_timer_interrupt;
-	setup_irq(IRQ_TICK, &timer_irq);
-}
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/timex.h b/include/asm-arm/arch-anakin/timex.h
--- a/include/asm-arm/arch-anakin/timex.h	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,22 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/timex.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   09-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_TIMEX_H
-#define __ASM_ARCH_TIMEX_H
-
-/*
- * Timex specification for Anakin
- */
-#define CLOCK_TICK_RATE		(1000 / 8)
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/uncompress.h b/include/asm-arm/arch-anakin/uncompress.h
--- a/include/asm-arm/arch-anakin/uncompress.h	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,58 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/uncompress.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   10-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_UNCOMPRESS_H
-#define __ASM_ARCH_UNCOMPRESS_H
-
-#include <linux/config.h>
-#include <asm/io.h>
-#include <asm/arch/serial_reg.h>
-
-#ifndef CONFIG_ANAKIN_DEFAULT_BAUDRATE
-#define CONFIG_ANAKIN_DEFAULT_BAUDRATE	9600
-#endif
-
-static inline void
-putc(int c)
-{
-	while (!(__raw_readl(IO_START + UART0 + 0x10) & TXEMPTY));
-	__raw_writel(c, IO_START + UART0 + 0x14);
-	__raw_writel(__raw_readl(IO_START + UART0 + 0x18)
-			| SENDREQUEST, IO_START + UART0 + 0x18);
-}
-
-static void
-puts(const char *s)
-{
-	int c;
-
-	while ((c = *s++)) {
-		putc(c);
-		if (c == '\n') putc('\r');
-	}
-}
-
-static void
-arch_decomp_setup(void)
-{
-	__raw_writel(__raw_readl(IO_START + UART0 + 0x10) & ~PRESCALER
-			| SETBAUD(CONFIG_ANAKIN_DEFAULT_BAUDRATE),
-			IO_START + UART0 + 0x10);
-	__raw_writel(__raw_readl(IO_START + UART0 + 0x18) & ~(IRQENABLE
-			| RTS | DTR | BLOCKRX | PARITY),
-			IO_START + UART0 + 0x18);
-}
-
-#define arch_decomp_wdog()
-
-#endif
diff -Nru a/include/asm-arm/arch-anakin/vmalloc.h b/include/asm-arm/arch-anakin/vmalloc.h
--- a/include/asm-arm/arch-anakin/vmalloc.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-/*
- *  linux/include/asm-arm/arch-anakin/vmalloc.h
- *
- *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
- *
- * 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.
- *
- *  Changelog:
- *   09-Apr-2001 TTC	Created
- */
-
-#ifndef __ASM_ARCH_VMALLOC_H
-#define __ASM_ARCH_VMALLOC_H
-
-/*
- * VMALLOC_ARCH_OFFSET must be set to VMALLOC_OFFSET (check
- * linux/arch/arm/kernel/traps.c)
- */
-#define VMALLOC_ARCH_OFFSET	(8 * 1024 * 1024)
-#define VMALLOC_START		(((unsigned long) (high_memory) + VMALLOC_ARCH_OFFSET) & ~(VMALLOC_ARCH_OFFSET - 1))
-#define VMALLOC_END		(PAGE_OFFSET + 0x10000000)
-
-#define MODULE_START	(PAGE_OFFSET - 16*1048576)
-#define MODULE_END	(PAGE_OFFSET)
-
-#endif
diff -Nru a/include/asm-arm/arch-ebsa285/irqs.h b/include/asm-arm/arch-ebsa285/irqs.h
--- a/include/asm-arm/arch-ebsa285/irqs.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-arm/arch-ebsa285/irqs.h	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/include/asm-arm/arch-shark/irqs.h b/include/asm-arm/arch-shark/irqs.h
--- a/include/asm-arm/arch-shark/irqs.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-arm/arch-shark/irqs.h	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
--- a/include/asm-arm/dma-mapping.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-arm/dma-mapping.h	Sat Apr  3 19:38:40 2004
@@ -14,8 +14,6 @@
  * devices.  This is the "generic" version.  The PCI specific version
  * is in pci.h
  */
-extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, unsigned long flags);
-extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
 extern void consistent_sync(void *kaddr, size_t size, int rw);
 
 /*
@@ -26,8 +24,10 @@
 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
 
@@ -97,12 +97,26 @@
  * References to memory and mappings associated with cpu_addr/handle
  * during and after this call executing are illegal.
  */
-static inline void
+extern void
 dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
-		  dma_addr_t handle)
-{
-	consistent_free(cpu_addr, size, handle);
-}
+		  dma_addr_t handle);
+
+/**
+ * dma_alloc_writecombine - allocate writecombining memory for DMA
+ * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices
+ * @size: required memory size
+ * @handle: bus-specific DMA address
+ *
+ * Allocate some uncached, buffered memory for a device for
+ * performing DMA.  This function allocates pages, and will
+ * return the CPU-viewed address, and sets @handle to be the
+ * device-viewed address.
+ */
+extern void *
+dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t *handle, int gfp);
+
+#define dma_free_writecombine(dev,size,cpu_addr,handle) \
+	dma_free_coherent(dev,size,cpu_addr,handle)
 
 /**
  * dma_map_single - map a single buffer for streaming DMA
@@ -115,7 +129,8 @@
  * 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 +155,8 @@
  * 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 +220,7 @@
  *
  * 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 +230,7 @@
  *       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 +262,7 @@
  *
  * 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 +277,7 @@
 }
 
 /**
- * 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 +286,31 @@
  * 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 +318,7 @@
 }
 
 /**
- * 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 +327,17 @@
  * 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(dev, sg, nents, dir);
+		sa1111_dma_sync_sg_for_cpu(dev, sg, nents, dir);
 		return;
 	}
 
@@ -316,6 +345,31 @@
 		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_for_device(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);
+	}
+}
+
+/*
+ * DMA errors are defined by all-bits-set in the DMA address.
+ */
+static inline int dma_mapping_error(dma_addr_t dma_addr)
+{
+	return dma_addr == ~0;
 }
 
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-arm/hardirq.h b/include/asm-arm/hardirq.h
--- a/include/asm-arm/hardirq.h	Sat Apr  3 19:38:44 2004
+++ b/include/asm-arm/hardirq.h	Sat Apr  3 19:38:44 2004
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 #include <linux/cache.h>
 #include <linux/threads.h>
+#include <asm/irq.h>
 
 typedef struct {
 	unsigned int __softirq_pending;
diff -Nru a/include/asm-arm/hardware/amba.h b/include/asm-arm/hardware/amba.h
--- a/include/asm-arm/hardware/amba.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-arm/hardware/amba.h	Sat Apr  3 19:38:55 2004
@@ -15,6 +15,7 @@
 struct amba_device {
 	struct device		dev;
 	struct resource		res;
+	u64			dma_mask;
 	unsigned int		periphid;
 	unsigned int		irq[AMBA_NR_IRQS];
 };
diff -Nru a/include/asm-arm/system.h b/include/asm-arm/system.h
--- a/include/asm-arm/system.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-arm/system.h	Sat Apr  3 19:38:41 2004
@@ -93,6 +93,14 @@
 extern unsigned long cr_no_alignment;	/* defined in entry-armv.S */
 extern unsigned long cr_alignment;	/* defined in entry-armv.S */
 
+#define UDBG_UNDEFINED	(1 << 0)
+#define UDBG_SYSCALL	(1 << 1)
+#define UDBG_BADABORT	(1 << 2)
+#define UDBG_SEGV	(1 << 3)
+#define UDBG_BUS	(1 << 4)
+
+extern unsigned int user_debug;
+
 #if __LINUX_ARM_ARCH__ >= 4
 #define vectors_base()	((cr_alignment & CR_V) ? 0xffff0000 : 0)
 #else
diff -Nru a/include/asm-arm26/thread_info.h b/include/asm-arm26/thread_info.h
--- a/include/asm-arm26/thread_info.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-arm26/thread_info.h	Sat Apr  3 19:38:42 2004
@@ -81,8 +81,6 @@
 
 /* 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 -Nru a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h
--- a/include/asm-generic/dma-mapping.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-generic/dma-mapping.h	Sat Apr  3 19:38:55 2004
@@ -103,21 +103,47 @@
 }
 
 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);
+}
+
+static inline int
+dma_mapping_error(dma_addr_t dma_addr)
+{
+	return pci_dma_mapping_error(dma_addr);
 }
 
 /* Now for the API extensions over the pci_ one */
@@ -135,12 +161,21 @@
 }
 
 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 -Nru a/include/asm-generic/pci-dma-compat.h b/include/asm-generic/pci-dma-compat.h
--- a/include/asm-generic/pci-dma-compat.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-generic/pci-dma-compat.h	Sat Apr  3 19:38:41 2004
@@ -71,17 +71,37 @@
 }
 
 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(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)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_for_device(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction);
+}
+
+static inline int
+pci_dma_mapping_error(dma_addr_t dma_addr)
+{
+	return dma_mapping_error(dma_addr);
 }
 
 #endif
diff -Nru a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
--- a/include/asm-generic/siginfo.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-generic/siginfo.h	Sat Apr  3 19:38:42 2004
@@ -26,8 +26,13 @@
 #define __ARCH_SI_UID_T	uid_t
 #endif
 
+/*
+ * The default "si_band" type is "long", as specified by POSIX.
+ * However, some architectures want to override this to "int"
+ * for historical compatibility reasons, so we allow that.
+ */
 #ifndef __ARCH_SI_BAND_T
-#define __ARCH_SI_BAND_T int
+#define __ARCH_SI_BAND_T long
 #endif
 
 #ifndef HAVE_ARCH_SIGINFO_T
diff -Nru a/include/asm-h8300/bitops.h b/include/asm-h8300/bitops.h
--- a/include/asm-h8300/bitops.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-h8300/bitops.h	Sat Apr  3 19:38:42 2004
@@ -89,21 +89,21 @@
 	case BIT:						     \
 	__asm__("stc ccr,%w1\n\t"				     \
 		"orc #0x80,ccr\n\t"				     \
-		"bld #" #BIT ",@%3\n\t"				     \
-		OP " #" #BIT ",@%3\n\t"				     \
+		"bld #" #BIT ",@%4\n\t"				     \
+		OP " #" #BIT ",@%4\n\t"				     \
 		"rotxl.l %0\n\t"				     \
 		"ldc %w1,ccr"					     \
-		: "=r"(retval),"=&r"(ccrsave)			     \
+		: "=r"(retval),"=&r"(ccrsave),"=m"(*b_addr)	     \
 		: "0" (retval),"r" (b_addr)			     \
 		: "memory");                                         \
         break;
 
 #define H8300_GEN_TEST_BITOP_CONST(OP,BIT)			     \
 	case BIT:						     \
-	__asm__("bld #" #BIT ",@%2\n\t"				     \
-		OP " #" #BIT ",@%2\n\t"				     \
+	__asm__("bld #" #BIT ",@%3\n\t"				     \
+		OP " #" #BIT ",@%3\n\t"				     \
 		"rotxl.l %0\n\t"				     \
-		: "=r"(retval)					     \
+		: "=r"(retval),"=m"(*b_addr)			     \
 		: "0" (retval),"r" (b_addr)			     \
 		: "memory");                                         \
         break;
@@ -129,13 +129,13 @@
 	} else {						     \
 		__asm__("stc ccr,%w1\n\t"			     \
 			"orc #0x80,ccr\n\t"			     \
-			"btst %w4,@%3\n\t"			     \
-			OP " %w4,@%3\n\t"			     \
+			"btst %w5,@%4\n\t"			     \
+			OP " %w5,@%4\n\t"			     \
 			"beq 1f\n\t"				     \
 			"inc.l #1,%0\n"				     \
 			"1:\n\t"				     \
 			"ldc %w1,ccr"				     \
-			: "=r"(retval),"=&r"(ccrsave)		     \
+			: "=r"(retval),"=&r"(ccrsave),"=m"(*b_addr)  \
 			: "0" (retval),"r" (b_addr),"r"(nr)	     \
 			: "memory");				     \
 	}							     \
@@ -159,12 +159,12 @@
 			H8300_GEN_TEST_BITOP_CONST(OP,7) 	     \
 		}						     \
 	} else {						     \
-		__asm__("btst %w3,@%2\n\t"			     \
-			OP " %w3,@%2\n\t"			     \
+		__asm__("btst %w4,@%3\n\t"			     \
+			OP " %w4,@%3\n\t"			     \
 			"beq 1f\n\t"				     \
 			"inc.l #1,%0\n"				     \
 			"1:"					     \
-			: "=r"(retval)				     \
+			: "=r"(retval),"=m"(*b_addr)		     \
 			: "0" (retval),"r" (b_addr),"r"(nr)	     \
 			: "memory");				     \
 	}							     \
@@ -183,7 +183,7 @@
 
 static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+	unsigned long *p = (unsigned long *)(((unsigned long)addr + (offset >> 3)) & ~3);
 	unsigned long result = offset & ~31UL;
 	unsigned long tmp;
 
diff -Nru a/include/asm-h8300/dma-mapping.h b/include/asm-h8300/dma-mapping.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-h8300/dma-mapping.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1 @@
+#include <asm-generic/dma-mapping-broken.h>
diff -Nru a/include/asm-h8300/irq.h b/include/asm-h8300/irq.h
--- a/include/asm-h8300/irq.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-h8300/irq.h	Sat Apr  3 19:38:41 2004
@@ -13,6 +13,16 @@
 #define EXT_IRQ5 17
 #define EXT_IRQ6 18
 #define EXT_IRQ7 19
+#define EXT_IRQS 5
+
+#include <asm/regs306x.h>
+#define h8300_clear_isr(irq)                                                \
+do {                                                                        \
+	if (irq >= EXT_IRQ0 && irq <= EXT_IRQ5)                             \
+		*(volatile unsigned char *)ISR &= ~(1 << (irq - EXT_IRQ0)); \
+} while(0)
+
+#define IER_REGS *(volatile unsigned char *)IER
 #endif
 #if defined(CONFIG_CPU_H8S)
 #define NR_IRQS 128
@@ -32,6 +42,16 @@
 #define EXT_IRQ13 29
 #define EXT_IRQ14 30
 #define EXT_IRQ15 31
+#define EXT_IRQS 15
+
+#include <asm/regs267x.h>
+#define h8300_clear_isr(irq)                                                 \
+do {                                                                         \
+	if (irq >= EXT_IRQ0 && irq <= EXT_IRQ15)                             \
+		*(volatile unsigned short *)ISR &= ~(1 << (irq - EXT_IRQ0)); \
+} while(0)
+
+#define IER_REGS *(volatile unsigned short *)IER
 #endif
 
 static __inline__ int irq_canonicalize(int irq)
diff -Nru a/include/asm-h8300/traps.h b/include/asm-h8300/traps.h
--- a/include/asm-h8300/traps.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-h8300/traps.h	Sat Apr  3 19:38:56 2004
@@ -20,9 +20,18 @@
 #define VECTOR(address) ((JMP_OP)|((unsigned long)address))
 #define REDIRECT(address) ((JSR_OP)|((unsigned long)address))
 
+#define TRACE_VEC 5
+
 #define TRAP0_VEC 8
 #define TRAP1_VEC 9
 #define TRAP2_VEC 10
 #define TRAP3_VEC 11
+
+#if defined(__H8300H__)
+#define NR_TRAPS 12
+#endif
+#if defined(__H8300S__)
+#define NR_TRAPS 16
+#endif
 
 #endif /* _H8300_TRAPS_H */
diff -Nru a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h
--- a/include/asm-h8300/unistd.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-h8300/unistd.h	Sat Apr  3 19:38:43 2004
@@ -490,7 +490,6 @@
 			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 -Nru a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h
--- a/include/asm-i386/acpi.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-i386/acpi.h	Sat Apr  3 19:38:55 2004
@@ -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
 
@@ -52,42 +54,36 @@
 #define ACPI_ENABLE_IRQS()  local_irq_enable()
 #define ACPI_FLUSH_CPU_CACHE()	wbinvd()
 
-/*
- * A brief explanation as GNU inline assembly is a bit hairy
- *  %0 is the output parameter in EAX ("=a")
- *  %1 and %2 are the input parameters in ECX ("c")
- *  and an immediate value ("i") respectively
- *  All actual register references are preceded with "%%" as in "%%edx"
- *  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
@@ -111,13 +107,17 @@
 extern int acpi_ioapic;
 extern int acpi_noirq;
 extern int acpi_strict;
+extern int acpi_disabled;
+extern int acpi_ht;
+static inline void disable_acpi(void) { acpi_disabled = 1; acpi_ht = 0; }
 
 /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
 #define FIX_ACPI_PAGES 4
 
+extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq);
 #ifdef CONFIG_X86_IO_APIC
 extern int skip_ioapic_setup;
-extern int acpi_irq_to_vector(u32 irq);
+extern int acpi_irq_to_vector(u32 irq);	/* deprecated in favor of acpi_gsi_to_irq */
 
 static inline void disable_ioapic_setup(void)
 {
diff -Nru a/include/asm-i386/dma-mapping.h b/include/asm-i386/dma-mapping.h
--- a/include/asm-i386/dma-mapping.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-i386/dma-mapping.h	Sat Apr  3 19:38:56 2004
@@ -70,26 +70,50 @@
 }
 
 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();
+}
+
+static inline int
+dma_mapping_error(dma_addr_t dma_addr)
+{
+	return 0;
 }
 
 static inline int
diff -Nru a/include/asm-i386/edd.h b/include/asm-i386/edd.h
--- a/include/asm-i386/edd.h	Sat Apr  3 19:38:41 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,176 +0,0 @@
-/*
- * linux/include/asm-i386/edd.h
- *  Copyright (C) 2002, 2003 Dell Inc.
- *  by Matt Domsch <Matt_Domsch@dell.com>
- *
- * structures and definitions for the int 13h, ax={41,48}h
- * BIOS Enhanced Disk Drive Services
- * This is based on the T13 group document D1572 Revision 0 (August 14 2002)
- * available at http://www.t13.org/docs2002/d1572r0.pdf.  It is
- * very similar to D1484 Revision 3 http://www.t13.org/docs2002/d1484r3.pdf
- *
- * In a nutshell, arch/i386/boot/setup.S populates a scratch table
- * in the empty_zero_block that contains a list of BIOS-enumerated
- * boot devices.
- * In arch/i386/kernel/setup.c, this information is
- * transferred into the edd structure, and in arch/i386/kernel/edd.c, that
- * information is used to identify BIOS boot disk.  The code in setup.S
- * is very sensitive to the size of these structures.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License v2.0 as published by
- * the Free Software Foundation
- *
- * 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.
- *
- */
-#ifndef _ASM_I386_EDD_H
-#define _ASM_I386_EDD_H
-
-#define EDDNR 0x1e9		/* addr of number of edd_info structs at EDDBUF
-				   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 EDDPARMSIZE 74
-#define CHECKEXTENSIONSPRESENT 0x41
-#define GETDEVICEPARAMETERS 0x48
-#define EDDMAGIC1 0x55AA
-#define EDDMAGIC2 0xAA55
-
-#define READ_SECTORS 0x02
-#define MBR_SIG_OFFSET 0x1B8
-#define DISK80_SIG_BUFFER 0x2cc
-#ifndef __ASSEMBLY__
-
-#define EDD_EXT_FIXED_DISK_ACCESS           (1 << 0)
-#define EDD_EXT_DEVICE_LOCKING_AND_EJECTING (1 << 1)
-#define EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT (1 << 2)
-#define EDD_EXT_64BIT_EXTENSIONS            (1 << 3)
-
-#define EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT (1 << 0)
-#define EDD_INFO_GEOMETRY_VALID                (1 << 1)
-#define EDD_INFO_REMOVABLE                     (1 << 2)
-#define EDD_INFO_WRITE_VERIFY                  (1 << 3)
-#define EDD_INFO_MEDIA_CHANGE_NOTIFICATION     (1 << 4)
-#define EDD_INFO_LOCKABLE                      (1 << 5)
-#define EDD_INFO_NO_MEDIA_PRESENT              (1 << 6)
-#define EDD_INFO_USE_INT13_FN50                (1 << 7)
-
-struct edd_device_params {
-	u16 length;
-	u16 info_flags;
-	u32 num_default_cylinders;
-	u32 num_default_heads;
-	u32 sectors_per_track;
-	u64 number_of_sectors;
-	u16 bytes_per_sector;
-	u32 dpte_ptr;		/* 0xFFFFFFFF for our purposes */
-	u16 key;		/* = 0xBEDD */
-	u8 device_path_info_length;	/* = 44 */
-	u8 reserved2;
-	u16 reserved3;
-	u8 host_bus_type[4];
-	u8 interface_type[8];
-	union {
-		struct {
-			u16 base_address;
-			u16 reserved1;
-			u32 reserved2;
-		} __attribute__ ((packed)) isa;
-		struct {
-			u8 bus;
-			u8 slot;
-			u8 function;
-			u8 channel;
-			u32 reserved;
-		} __attribute__ ((packed)) pci;
-		/* pcix is same as pci */
-		struct {
-			u64 reserved;
-		} __attribute__ ((packed)) ibnd;
-		struct {
-			u64 reserved;
-		} __attribute__ ((packed)) xprs;
-		struct {
-			u64 reserved;
-		} __attribute__ ((packed)) htpt;
-		struct {
-			u64 reserved;
-		} __attribute__ ((packed)) unknown;
-	} interface_path;
-	union {
-		struct {
-			u8 device;
-			u8 reserved1;
-			u16 reserved2;
-			u32 reserved3;
-			u64 reserved4;
-		} __attribute__ ((packed)) ata;
-		struct {
-			u8 device;
-			u8 lun;
-			u8 reserved1;
-			u8 reserved2;
-			u32 reserved3;
-			u64 reserved4;
-		} __attribute__ ((packed)) atapi;
-		struct {
-			u16 id;
-			u64 lun;
-			u16 reserved1;
-			u32 reserved2;
-		} __attribute__ ((packed)) scsi;
-		struct {
-			u64 serial_number;
-			u64 reserved;
-		} __attribute__ ((packed)) usb;
-		struct {
-			u64 eui;
-			u64 reserved;
-		} __attribute__ ((packed)) i1394;
-		struct {
-			u64 wwid;
-			u64 lun;
-		} __attribute__ ((packed)) fibre;
-		struct {
-			u64 identity_tag;
-			u64 reserved;
-		} __attribute__ ((packed)) i2o;
-		struct {
-			u32 array_number;
-			u32 reserved1;
-			u64 reserved2;
-		} __attribute__ ((packed)) raid;
-		struct {
-			u8 device;
-			u8 reserved1;
-			u16 reserved2;
-			u32 reserved3;
-			u64 reserved4;
-		} __attribute__ ((packed)) sata;
-		struct {
-			u64 reserved1;
-			u64 reserved2;
-		} __attribute__ ((packed)) unknown;
-	} device_path;
-	u8 reserved4;
-	u8 checksum;
-} __attribute__ ((packed));
-
-struct edd_info {
-	u8 device;
-	u8 version;
-	u16 interface_support;
-	struct edd_device_params params;
-} __attribute__ ((packed));
-
-extern struct edd_info edd[EDDMAXNR];
-extern unsigned char eddnr;
-extern unsigned int edd_disk80_sig;
-#endif				/*!__ASSEMBLY__ */
-
-#endif				/* _ASM_I386_EDD_H */
diff -Nru a/include/asm-i386/io.h b/include/asm-i386/io.h
--- a/include/asm-i386/io.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-i386/io.h	Sat Apr  3 19:38:56 2004
@@ -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 @@
  * 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 @@
 #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 @@
  * 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 -Nru a/include/asm-i386/module.h b/include/asm-i386/module.h
--- a/include/asm-i386/module.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-i386/module.h	Sat Apr  3 19:38:41 2004
@@ -36,7 +36,7 @@
 #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 "
diff -Nru a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
--- a/include/asm-i386/mpspec.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-i386/mpspec.h	Sat Apr  3 19:38:40 2004
@@ -30,17 +30,10 @@
 #ifdef CONFIG_ACPI_BOOT
 extern void mp_register_lapic (u8 id, u8 enabled);
 extern void mp_register_lapic_address (u64 address);
-extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base);
-extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq);
+extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
+extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
 extern void mp_config_acpi_legacy_irqs (void);
 extern void mp_parse_prt (void);
-
-#ifdef CONFIG_X86_IO_APIC
-extern void mp_config_ioapic_for_sci(int irq);
-#else
-static inline void mp_config_ioapic_for_sci(int irq)
-{ }
-#endif
 #endif /*CONFIG_ACPI_BOOT*/
 
 #define PHYSID_ARRAY_SIZE	BITS_TO_LONGS(MAX_APICS)
diff -Nru a/include/asm-i386/node.h b/include/asm-i386/node.h
--- a/include/asm-i386/node.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-i386/node.h	Sat Apr  3 19:38:42 2004
@@ -12,8 +12,12 @@
 extern struct i386_node node_devices[MAX_NUMNODES];
 
 static inline int arch_register_node(int num){
-	int p_node = parent_node(num);
+	int p_node;
 	struct node *parent = NULL;
+
+	if (!node_online(num))
+		return 0;
+	p_node = parent_node(num);
 
 	if (p_node != num)
 		parent = &node_devices[p_node].node;
diff -Nru a/include/asm-i386/pci.h b/include/asm-i386/pci.h
--- a/include/asm-i386/pci.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-i386/pci.h	Sat Apr  3 19:38:43 2004
@@ -60,27 +60,32 @@
 /* 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 -Nru a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
--- a/include/asm-i386/pgtable.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-i386/pgtable.h	Sat Apr  3 19:38:54 2004
@@ -173,8 +173,8 @@
  */
 #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)
diff -Nru a/include/asm-i386/setup.h b/include/asm-i386/setup.h
--- a/include/asm-i386/setup.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-i386/setup.h	Sat Apr  3 19:38:45 2004
@@ -16,10 +16,22 @@
 #define MAXMEM_PFN	PFN_DOWN(MAXMEM)
 #define MAX_NONPAE_PFN	(1 << 20)
 
+#define PARAM_SIZE 2048
+#define COMMAND_LINE_SIZE 256
+
+#define OLD_CL_MAGIC_ADDR	0x90020
+#define OLD_CL_MAGIC		0xA33F
+#define OLD_CL_BASE_ADDR	0x90000
+#define OLD_CL_OFFSET		0x90022
+#define NEW_CL_POINTER		0x228	/* Relative to real mode data */
+
+#ifndef __ASSEMBLY__
 /*
  * This is set up by the setup-routine at boot-time
  */
-#define PARAM	((unsigned char *)empty_zero_page)
+extern unsigned char boot_params[PARAM_SIZE];
+
+#define PARAM	(boot_params)
 #define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
 #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
 #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
@@ -47,7 +59,7 @@
 #define DISK80_SIGNATURE (*(unsigned int*) (PARAM+DISK80_SIG_BUFFER))
 #define EDD_NR     (*(unsigned char *) (PARAM+EDDNR))
 #define EDD_BUF     ((struct edd_info *) (PARAM+EDDBUF))
-#define COMMAND_LINE ((char *) (PARAM+2048))
-#define COMMAND_LINE_SIZE 256
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* _i386_SETUP_H */
diff -Nru a/include/asm-i386/system.h b/include/asm-i386/system.h
--- a/include/asm-i386/system.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-i386/system.h	Sat Apr  3 19:38:40 2004
@@ -241,6 +241,7 @@
 
 #ifdef CONFIG_X86_CMPXCHG
 #define __HAVE_ARCH_CMPXCHG 1
+#endif
 
 static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 				      unsigned long new, int size)
@@ -273,10 +274,6 @@
 	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
 					(unsigned long)(n),sizeof(*(ptr))))
     
-#else
-/* Compiling for a 386 proper.	Is it worth implementing via cli/sti?  */
-#endif
-
 #ifdef __KERNEL__
 struct alt_instr { 
 	__u8 *instr; 		/* original instruction */
diff -Nru a/include/asm-i386/topology.h b/include/asm-i386/topology.h
--- a/include/asm-i386/topology.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-i386/topology.h	Sat Apr  3 19:38:41 2004
@@ -66,6 +66,9 @@
 	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 -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
--- a/include/asm-i386/unistd.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-i386/unistd.h	Sat Apr  3 19:38:45 2004
@@ -375,6 +375,7 @@
 
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <linux/linkage.h>
 #include <asm/ptrace.h>
 
 /*
diff -Nru a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
--- a/include/asm-ia64/acpi.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ia64/acpi.h	Sat Apr  3 19:38:55 2004
@@ -88,12 +88,15 @@
 #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq)				\
 	((Acq) = ia64_acpi_release_global_lock((unsigned int *) GLptr))
 
+#define acpi_disabled 0	/* ACPI always enabled on IA64 */
 #define acpi_strict 1	/* no ACPI spec workarounds on IA64 */
+static inline void disable_acpi(void) { }
 
 const char *acpi_get_sysname (void);
 int acpi_request_vector (u32 int_type);
 int acpi_register_irq (u32 gsi, u32 polarity, u32 trigger);
-int acpi_irq_to_vector (u32 irq);
+int acpi_irq_to_vector (u32 irq); /* deprecated in favor of acpi_gsi_to_irq */
+int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 
 #ifdef CONFIG_ACPI_NUMA
 /* Proximity bitmap length; _PXM is at most 255 (8 bit)*/
diff -Nru a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h
--- a/include/asm-ia64/compat.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ia64/compat.h	Sat Apr  3 19:38:55 2004
@@ -11,6 +11,7 @@
 typedef s32		compat_ssize_t;
 typedef s32		compat_time_t;
 typedef s32		compat_clock_t;
+typedef s32		compat_key_t;
 typedef s32		compat_pid_t;
 typedef u16		compat_uid_t;
 typedef u16		compat_gid_t;
@@ -115,6 +116,64 @@
 
 #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,
diff -Nru a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h
--- a/include/asm-ia64/dma-mapping.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-ia64/dma-mapping.h	Sat Apr  3 19:38:54 2004
@@ -2,7 +2,7 @@
 #define _ASM_IA64_DMA_MAPPING_H
 
 /*
- * Copyright (C) 2003 Hewlett-Packard Co
+ * Copyright (C) 2003-2004 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -14,8 +14,11 @@
 #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_mapping_error	platform_dma_mapping_error
 
 #define dma_map_page(dev, pg, off, size, dir)				\
 	dma_map_single(dev, page_address(pg) + (off), (size), (dir))
@@ -27,8 +30,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 -Nru a/include/asm-ia64/gcc_intrin.h b/include/asm-ia64/gcc_intrin.h
--- a/include/asm-ia64/gcc_intrin.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-ia64/gcc_intrin.h	Sat Apr  3 19:38:43 2004
@@ -23,6 +23,8 @@
 extern void ia64_bad_param_for_setreg (void);
 extern void ia64_bad_param_for_getreg (void);
 
+register unsigned long ia64_r13 asm ("r13");
+
 #define ia64_setreg(regnum, val)						\
 ({										\
 	switch (regnum) {							\
@@ -67,10 +69,7 @@
 		asm volatile ("mov %0=psr" : "=r"(ia64_intri_res));		\
 		break;								\
 	case _IA64_REG_TP:	/* for current() */				\
-		{								\
-			register __u64 ia64_r13 asm ("r13");			\
-			ia64_intri_res = ia64_r13;				\
-		}								\
+		ia64_intri_res = ia64_r13;					\
 		break;								\
 	case _IA64_REG_AR_KR0 ... _IA64_REG_AR_EC:				\
 		asm volatile ("mov %0=ar%1" : "=r" (ia64_intri_res)		\
diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h
--- a/include/asm-ia64/hardirq.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ia64/hardirq.h	Sat Apr  3 19:38:42 2004
@@ -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())
@@ -96,14 +94,6 @@
 # define in_atomic()		(preempt_count() != 0)
 # 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);
diff -Nru a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
--- a/include/asm-ia64/machvec.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-ia64/machvec.h	Sat Apr  3 19:38:43 2004
@@ -4,7 +4,7 @@
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
  * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
- * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co.
+ * Copyright (C) 1999-2001, 2003-2004 Hewlett-Packard Co.
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #ifndef _ASM_IA64_MACHVEC_H
@@ -21,12 +21,8 @@
 struct page;
 
 typedef void ia64_mv_setup_t (char **);
-typedef void ia64_mv_cpu_init_t(void);
+typedef void ia64_mv_cpu_init_t (void);
 typedef void ia64_mv_irq_init_t (void);
-typedef void ia64_mv_mca_init_t (void);
-typedef void ia64_mv_mca_handler_t (void);
-typedef void ia64_mv_cmci_handler_t (int, void *, struct pt_regs *);
-typedef void ia64_mv_log_print_t (void);
 typedef void ia64_mv_send_ipi_t (int, int, int, int);
 typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *);
 typedef void ia64_mv_global_tlb_purge_t (unsigned long, unsigned long, unsigned long);
@@ -42,8 +38,11 @@
 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_mapping_error (dma_addr_t dma_addr);
 typedef int ia64_mv_dma_supported (struct device *, u64);
 
 /*
@@ -71,7 +70,10 @@
 typedef unsigned long ia64_mv_readq_relaxed_t (void *);
 
 extern void machvec_noop (void);
-extern void machvec_memory_fence (void);
+extern void machvec_setup (char **);
+extern void machvec_timer_interrupt (int, void *, struct pt_regs *);
+extern void machvec_dma_sync_single (struct device *, dma_addr_t, size_t, int);
+extern void machvec_dma_sync_sg (struct device *, struct scatterlist *, int, int);
 
 # if defined (CONFIG_IA64_HP_SIM)
 #  include <asm/machvec_hpsim.h>
@@ -90,10 +92,6 @@
 #  define platform_setup	ia64_mv.setup
 #  define platform_cpu_init	ia64_mv.cpu_init
 #  define platform_irq_init	ia64_mv.irq_init
-#  define platform_mca_init	ia64_mv.mca_init
-#  define platform_mca_handler	ia64_mv.mca_handler
-#  define platform_cmci_handler	ia64_mv.cmci_handler
-#  define platform_log_print	ia64_mv.log_print
 #  define platform_send_ipi	ia64_mv.send_ipi
 #  define platform_timer_interrupt	ia64_mv.timer_interrupt
 #  define platform_global_tlb_purge	ia64_mv.global_tlb_purge
@@ -104,8 +102,11 @@
 #  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_mapping_error		ia64_mv.dma_mapping_error
 #  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
@@ -136,10 +137,6 @@
 	ia64_mv_setup_t *setup;
 	ia64_mv_cpu_init_t *cpu_init;
 	ia64_mv_irq_init_t *irq_init;
-	ia64_mv_mca_init_t *mca_init;
-	ia64_mv_mca_handler_t *mca_handler;
-	ia64_mv_cmci_handler_t *cmci_handler;
-	ia64_mv_log_print_t *log_print;
 	ia64_mv_send_ipi_t *send_ipi;
 	ia64_mv_timer_interrupt_t *timer_interrupt;
 	ia64_mv_global_tlb_purge_t *global_tlb_purge;
@@ -150,8 +147,11 @@
 	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_for_cpu *dma_sync_single_for_cpu;
+	ia64_mv_dma_sync_sg_for_cpu *dma_sync_sg_for_cpu;
+	ia64_mv_dma_sync_single_for_device *dma_sync_single_for_device;
+	ia64_mv_dma_sync_sg_for_device *dma_sync_sg_for_device;
+	ia64_mv_dma_mapping_error *dma_mapping_error;
 	ia64_mv_dma_supported *dma_supported;
 	ia64_mv_irq_desc *irq_desc;
 	ia64_mv_irq_to_vector *irq_to_vector;
@@ -178,10 +178,6 @@
 	platform_setup,				\
 	platform_cpu_init,			\
 	platform_irq_init,			\
-	platform_mca_init,			\
-	platform_mca_handler,			\
-	platform_cmci_handler,			\
-	platform_log_print,			\
 	platform_send_ipi,			\
 	platform_timer_interrupt,		\
 	platform_global_tlb_purge,		\
@@ -192,8 +188,11 @@
 	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_mapping_error,			\
 	platform_dma_supported,			\
 	platform_irq_desc,			\
 	platform_irq_to_vector,			\
@@ -231,8 +230,11 @@
 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_mapping_error	swiotlb_dma_mapping_error;
 extern ia64_mv_dma_supported		swiotlb_dma_supported;
 
 /*
@@ -240,31 +242,20 @@
  * to update the machvec files for all existing platforms.
  */
 #ifndef platform_setup
-# define platform_setup		((ia64_mv_setup_t *) machvec_noop)
+# define platform_setup			machvec_setup
 #endif
 #ifndef platform_cpu_init
-# define platform_cpu_init	((ia64_mv_cpu_init_t *) machvec_noop)
+# define platform_cpu_init		machvec_noop
 #endif
 #ifndef platform_irq_init
-# define platform_irq_init	((ia64_mv_irq_init_t *) machvec_noop)
-#endif
-#ifndef platform_mca_init
-# define platform_mca_init	((ia64_mv_mca_init_t *) machvec_noop)
-#endif
-#ifndef platform_mca_handler
-# define platform_mca_handler	((ia64_mv_mca_handler_t *) machvec_noop)
-#endif
-#ifndef platform_cmci_handler
-# define platform_cmci_handler	((ia64_mv_cmci_handler_t *) machvec_noop)
-#endif
-#ifndef platform_log_print
-# define platform_log_print	((ia64_mv_log_print_t *) machvec_noop)
+# define platform_irq_init		machvec_noop
 #endif
+
 #ifndef platform_send_ipi
-# define platform_send_ipi	ia64_send_ipi	/* default to architected version */
+# define platform_send_ipi		ia64_send_ipi	/* default to architected version */
 #endif
 #ifndef platform_timer_interrupt
-# define platform_timer_interrupt 	((ia64_mv_timer_interrupt_t *) machvec_noop)
+# define platform_timer_interrupt 	machvec_timer_interrupt
 #endif
 #ifndef platform_global_tlb_purge
 # define platform_global_tlb_purge	ia64_global_tlb_purge /* default to architected version */
@@ -290,11 +281,20 @@
 #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_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_sync_sg
-# define platform_dma_sync_sg		swiotlb_sync_sg
+#ifndef platform_dma_mapping_error
+# define platform_dma_mapping_error		swiotlb_dma_mapping_error
 #endif
 #ifndef platform_dma_supported
 # define  platform_dma_supported	swiotlb_dma_supported
diff -Nru a/include/asm-ia64/machvec_hpzx1.h b/include/asm-ia64/machvec_hpzx1.h
--- a/include/asm-ia64/machvec_hpzx1.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-ia64/machvec_hpzx1.h	Sat Apr  3 19:38:41 2004
@@ -9,6 +9,7 @@
 extern ia64_mv_dma_map_sg		sba_map_sg;
 extern ia64_mv_dma_unmap_sg		sba_unmap_sg;
 extern ia64_mv_dma_supported		sba_dma_supported;
+extern ia64_mv_dma_mapping_error	sba_dma_mapping_error;
 
 /*
  * This stuff has dual use!
@@ -19,15 +20,18 @@
  */
 #define platform_name			"hpzx1"
 #define platform_setup			dig_setup
-#define platform_dma_init		((ia64_mv_dma_init *) machvec_noop)
+#define platform_dma_init		machvec_noop
 #define platform_dma_alloc_coherent	sba_alloc_coherent
 #define platform_dma_free_coherent	sba_free_coherent
 #define platform_dma_map_single		sba_map_single
 #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_supported		sba_dma_supported
+#define platform_dma_sync_single_for_cpu	machvec_dma_sync_single
+#define platform_dma_sync_sg_for_cpu		machvec_dma_sync_sg
+#define platform_dma_sync_single_for_device	machvec_dma_sync_single
+#define platform_dma_sync_sg_for_device		machvec_dma_sync_sg
+#define platform_dma_supported			sba_dma_supported
+#define platform_dma_mapping_error		sba_dma_mapping_error
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
diff -Nru a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
--- a/include/asm-ia64/machvec_sn2.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ia64/machvec_sn2.h	Sat Apr  3 19:38:42 2004
@@ -62,8 +62,11 @@
 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_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
 
 /*
@@ -105,8 +108,11 @@
 #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_mapping_error		sn_dma_mapping_error
 #define platform_dma_supported		sn_dma_supported
 
 #include <asm/sn/sn2/io.h>
diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
--- a/include/asm-ia64/pci.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ia64/pci.h	Sat Apr  3 19:38:55 2004
@@ -76,7 +76,8 @@
 #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 -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
--- a/include/asm-ia64/processor.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ia64/processor.h	Sat Apr  3 19:38:42 2004
@@ -148,35 +148,35 @@
 	__u32 softirq_pending;
 	__u64 itm_delta;	/* # of clock cycles between clock ticks */
 	__u64 itm_next;		/* interval timer mask value to use for next clock tick */
+	__u64 nsec_per_cyc;	/* (1000000000<<IA64_NSEC_PER_CYC_SHIFT)/itc_freq */
+	__u64 unimpl_va_mask;	/* mask of unimplemented virtual address bits (from PAL) */
+	__u64 unimpl_pa_mask;	/* mask of unimplemented physical address bits (from PAL) */
 	__u64 *pgd_quick;
 	__u64 *pmd_quick;
 	__u64 pgtable_cache_sz;
-	/* CPUID-derived information: */
-	__u64 ppn;
-	__u64 features;
-	__u8 number;
-	__u8 revision;
-	__u8 model;
-	__u8 family;
-	__u8 archrev;
-	char vendor[16];
 	__u64 itc_freq;		/* frequency of ITC counter */
 	__u64 proc_freq;	/* frequency of processor */
 	__u64 cyc_per_usec;	/* itc_freq/1000000 */
-	__u64 nsec_per_cyc;	/* (1000000000<<IA64_NSEC_PER_CYC_SHIFT)/itc_freq */
-	__u64 unimpl_va_mask;	/* mask of unimplemented virtual address bits (from PAL) */
-	__u64 unimpl_pa_mask;	/* mask of unimplemented physical address bits (from PAL) */
 	__u64 ptce_base;
 	__u32 ptce_count[2];
 	__u32 ptce_stride[2];
 	struct task_struct *ksoftirqd;	/* kernel softirq daemon for this CPU */
+
 #ifdef CONFIG_SMP
-	int cpu;
 	__u64 loops_per_jiffy;
-	__u64 ipi_count;
-	__u64 prof_counter;
-	__u64 prof_multiplier;
+	int cpu;
 #endif
+
+	/* CPUID-derived information: */
+	__u64 ppn;
+	__u64 features;
+	__u8 number;
+	__u8 revision;
+	__u8 model;
+	__u8 family;
+	__u8 archrev;
+	char vendor[16];
+
 #ifdef CONFIG_NUMA
 	struct ia64_node_data *node_data;
 #endif
@@ -678,7 +678,7 @@
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
 #define ARCH_HAS_SPINLOCK_PREFETCH
-#define PREFETCH_STRIDE 256
+#define PREFETCH_STRIDE			L1_CACHE_BYTES
 
 static inline void
 prefetch (const void *x)
diff -Nru a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h
--- a/include/asm-ia64/sal.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-ia64/sal.h	Sat Apr  3 19:38:56 2004
@@ -35,6 +35,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/bcd.h>
 #include <linux/spinlock.h>
 #include <linux/efi.h>
 
@@ -229,6 +230,10 @@
 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 @@
 
 /* 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 @@
 
 /* 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 -Nru a/include/asm-ia64/sn/router.h b/include/asm-ia64/sn/router.h
--- a/include/asm-ia64/sn/router.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ia64/sn/router.h	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/include/asm-ia64/sn/sndrv.h b/include/asm-ia64/sn/sndrv.h
--- a/include/asm-ia64/sn/sndrv.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-ia64/sn/sndrv.h	Sat Apr  3 19:38:43 2004
@@ -41,6 +41,11 @@
 #define SNDRV_SHUB_RESETSTATS		42
 #define SNDRV_SHUB_GETSTATS		43
 #define SNDRV_SHUB_GETNASID		44
+#define SNDRV_SHUB_GETMMR32            45
+#define SNDRV_SHUB_GETMMR64            46
+#define SNDRV_SHUB_GETMMR64_IO         47
+#define SNDRV_SHUB_PUTMMR64            48
+#define SNDRV_SHUB_PUTMMR64_IO         49
 
 /* Devices */
 #define SNDRV_UKNOWN_DEVICE		-1
diff -Nru a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h
--- a/include/asm-ia64/spinlock.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-ia64/spinlock.h	Sat Apr  3 19:38:41 2004
@@ -61,7 +61,7 @@
 		      "}\n\t"
 		      "cmpxchg4.acq r30 = [%1], r30, ar.ccv;;\n\t"
 		      "cmp4.ne p14, p0 = r30, r0\n"
-		      "(p14) brl.cond.spnt.many ia64_spinlock_contention_pre3_4"
+		      "(p14) brl.cond.spnt.many ia64_spinlock_contention_pre3_4;;"
 		      : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS);
 # endif /* CONFIG_MCKINLEY */
 #else
@@ -81,7 +81,7 @@
 		      "mov ar.ccv = r0;;\n\t"
 		      "cmpxchg4.acq r30 = [%0], r30, ar.ccv;;\n\t"
 		      "cmp4.ne p14, p0 = r30, r0\n\t"
-		      "(p14) brl.call.spnt.many b6=ia64_spinlock_contention"
+		      "(p14) brl.call.spnt.many b6=ia64_spinlock_contention;;"
 		      : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS);
 # endif /* CONFIG_MCKINLEY */
 #endif
diff -Nru a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h
--- a/include/asm-ia64/uaccess.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ia64/uaccess.h	Sat Apr  3 19:38:42 2004
@@ -292,16 +292,16 @@
 	int cont;	/* location-relative continuation addr.; if bit 2 is set, r9 is set to 0 */
 };
 
-extern void handle_exception (struct pt_regs *regs, const struct exception_table_entry *e);
+extern void ia64_handle_exception (struct pt_regs *regs, const struct exception_table_entry *e);
 extern const struct exception_table_entry *search_exception_tables (unsigned long addr);
 
 static inline int
-done_with_exception (struct pt_regs *regs)
+ia64_done_with_exception (struct pt_regs *regs)
 {
 	const struct exception_table_entry *e;
 	e = search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri);
 	if (e) {
-		handle_exception(regs, e);
+		ia64_handle_exception(regs, e);
 		return 1;
 	}
 	return 0;
diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
--- a/include/asm-ia64/unistd.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-ia64/unistd.h	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h
--- a/include/asm-m68k/bitops.h	Sat Apr  3 19:38:57 2004
+++ b/include/asm-m68k/bitops.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h
--- a/include/asm-m68k/irq.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-m68k/irq.h	Sat Apr  3 19:38:45 2004
@@ -76,10 +76,10 @@
 
 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
diff -Nru a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h
--- a/include/asm-m68k/unistd.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-m68k/unistd.h	Sat Apr  3 19:38:43 2004
@@ -374,7 +374,6 @@
 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 -Nru a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h
--- a/include/asm-m68knommu/unistd.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-m68knommu/unistd.h	Sat Apr  3 19:38:43 2004
@@ -416,7 +416,6 @@
 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 -Nru a/include/asm-mips/dma-mapping.h b/include/asm-mips/dma-mapping.h
--- a/include/asm-mips/dma-mapping.h	Sat Apr  3 19:38:44 2004
+++ b/include/asm-mips/dma-mapping.h	Sat Apr  3 19:38:44 2004
@@ -29,11 +29,17 @@
 	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 -Nru a/include/asm-mips/pci.h b/include/asm-mips/pci.h
--- a/include/asm-mips/pci.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-mips/pci.h	Sat Apr  3 19:38:54 2004
@@ -82,7 +82,9 @@
 	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 -Nru a/include/asm-mips/shmparam.h b/include/asm-mips/shmparam.h
--- a/include/asm-mips/shmparam.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-mips/shmparam.h	Sat Apr  3 19:38:55 2004
@@ -6,6 +6,8 @@
 #ifndef _ASM_SHMPARAM_H
 #define _ASM_SHMPARAM_H
 
+#define __ARCH_FORCE_SHMLBA	1
+
 #define	SHMLBA 0x40000			/* attach addr a multiple of this */
 
 #endif /* _ASM_SHMPARAM_H */
diff -Nru a/include/asm-parisc/dma-mapping.h b/include/asm-parisc/dma-mapping.h
--- a/include/asm-parisc/dma-mapping.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-parisc/dma-mapping.h	Sat Apr  3 19:38:42 2004
@@ -15,8 +15,10 @@
 	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 @@
 
 
 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 @@
 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 -Nru a/include/asm-parisc/floppy.h b/include/asm-parisc/floppy.h
--- a/include/asm-parisc/floppy.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-parisc/floppy.h	Sat Apr  3 19:38:43 2004
@@ -1,11 +1,22 @@
-/*
- * Architecture specific parts of the Floppy driver
+/*    Architecture specific parts of the Floppy driver
  *
- * 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.
+ *    Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *    Copyright (C) 2000 Matthew Wilcox (willy a debian . org)
+ *    Copyright (C) 2000 Dave Kennedy
  *
- * Copyright (C) 1995
+ *    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_FLOPPY_H
 #define __ASM_PARISC_FLOPPY_H
diff -Nru a/include/asm-parisc/grfioctl.h b/include/asm-parisc/grfioctl.h
--- a/include/asm-parisc/grfioctl.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-parisc/grfioctl.h	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h
--- a/include/asm-parisc/ide.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-parisc/ide.h	Sat Apr  3 19:38:42 2004
@@ -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)
 {
@@ -64,19 +41,8 @@
 	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
-static __inline__ void ide_init_default_hwifs(void)
-{
-#ifndef CONFIG_PCI
-	hw_regs_t hw;
-	int index;
-
-	for(index = 0; index < MAX_HWIFS; index++) {
-		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
-		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw);
-	}
-#endif
-}
+/* There are no standard ports. */
+static inline void ide_init_default_hwifs(void)	{ ; }
 
 #define ide_request_irq(irq,hand,flg,dev,id)	request_irq((irq),(hand),(flg),(dev),(id))
 #define ide_free_irq(irq,dev_id)		free_irq((irq), (dev_id))
@@ -93,7 +59,7 @@
 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 +67,7 @@
 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 +75,7 @@
 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 +83,7 @@
 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 -Nru a/include/asm-parisc/io.h b/include/asm-parisc/io.h
--- a/include/asm-parisc/io.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-parisc/io.h	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/include/asm-parisc/ioctl.h b/include/asm-parisc/ioctl.h
--- a/include/asm-parisc/ioctl.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-parisc/ioctl.h	Sat Apr  3 19:38:40 2004
@@ -1,7 +1,23 @@
-/* $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.
  *
- * 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.
+ *
+ *    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 -Nru a/include/asm-parisc/keyboard.h b/include/asm-parisc/keyboard.h
--- a/include/asm-parisc/keyboard.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/include/asm-parisc/md.h b/include/asm-parisc/md.h
--- a/include/asm-parisc/md.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/include/asm-parisc/namei.h b/include/asm-parisc/namei.h
--- a/include/asm-parisc/namei.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-parisc/namei.h	Sat Apr  3 19:38:43 2004
@@ -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 -Nru a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
--- a/include/asm-parisc/pci.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-parisc/pci.h	Sat Apr  3 19:38:54 2004
@@ -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 -Nru a/include/asm-parisc/semaphore.h b/include/asm-parisc/semaphore.h
--- a/include/asm-parisc/semaphore.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-parisc/semaphore.h	Sat Apr  3 19:38:40 2004
@@ -1,14 +1,28 @@
-#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
+ *
+ *    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 >
  *
- * (C) Copyright 1996 Linus Torvalds
+ *    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.
  *
- * PA-RISC version by Matthew Wilcox
+ *    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>
diff -Nru a/include/asm-parisc/shmparam.h b/include/asm-parisc/shmparam.h
--- a/include/asm-parisc/shmparam.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-parisc/shmparam.h	Sat Apr  3 19:38:42 2004
@@ -1,6 +1,8 @@
 #ifndef _ASMPARISC_SHMPARAM_H
 #define _ASMPARISC_SHMPARAM_H
 
+#define __ARCH_FORCE_SHMLBA 	1
+
 #define SHMLBA 0x00400000   /* attach addr needs to be 4 Mb aligned */
 
 #endif /* _ASMPARISC_SHMPARAM_H */
diff -Nru a/include/asm-parisc/superio.h b/include/asm-parisc/superio.h
--- a/include/asm-parisc/superio.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-parisc/superio.h	Sat Apr  3 19:38:42 2004
@@ -81,9 +81,12 @@
 	|| ((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 -Nru a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
--- a/include/asm-parisc/unistd.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-parisc/unistd.h	Sat Apr  3 19:38:40 2004
@@ -909,7 +909,6 @@
 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 -Nru a/include/asm-ppc/cputable.h b/include/asm-ppc/cputable.h
--- a/include/asm-ppc/cputable.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-ppc/cputable.h	Sat Apr  3 19:38:43 2004
@@ -90,10 +90,24 @@
 	.long 99b;				\
 	.previous
 
-#define END_FTR_SECTION_IFSET(msk)	END_FTR_SECTION((msk), (msk))
-#define END_FTR_SECTION_IFCLR(msk)	END_FTR_SECTION((msk), 0)
+#else
+
+#define BEGIN_FTR_SECTION		"98:\n"
+#define END_FTR_SECTION(msk, val)		\
+"99:\n"						\
+"	.section __ftr_fixup,\"a\";\n"		\
+"	.align 2;\n"				\
+"	.long "#msk";\n"			\
+"	.long "#val";\n"			\
+"	.long 98b;\n"			        \
+"	.long 99b;\n"	 		        \
+"	.previous\n"
+
 
 #endif /* __ASSEMBLY__ */
+
+#define END_FTR_SECTION_IFSET(msk)	END_FTR_SECTION((msk), (msk))
+#define END_FTR_SECTION_IFCLR(msk)	END_FTR_SECTION((msk), 0)
 
 #endif /* __ASM_PPC_CPUTABLE_H */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc/dma-mapping.h b/include/asm-ppc/dma-mapping.h
--- a/include/asm-ppc/dma-mapping.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ppc/dma-mapping.h	Sat Apr  3 19:38:55 2004
@@ -1 +1,187 @@
-#include <asm-generic/dma-mapping.h>
+/*
+ * This is based on both include/asm-sh/dma-mapping.h and
+ * include/asm-ppc/pci.h
+ */
+#ifndef __ASM_PPC_DMA_MAPPING_H
+#define __ASM_PPC_DMA_MAPPING_H
+
+#include <linux/config.h>
+/* we implement the API below in terms of the existing PCI one,
+ * so include it */
+#include <linux/pci.h>
+/* need struct page definitions */
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+#define dma_supported(dev, mask)	(1)
+
+static inline int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, mask))
+		return -EIO;
+
+	*dev->dma_mask = dma_mask;
+
+	return 0;
+}
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+				       dma_addr_t * dma_handle, int flag)
+{
+#ifdef CONFIG_PCI
+	if (dev && dev->bus == &pci_bus_type)
+		return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+#endif
+
+	return consistent_alloc(flag, size, dma_handle);
+}
+
+static inline void
+dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+		  dma_addr_t dma_handle)
+{
+#ifdef CONFIG_PCI
+	if (dev && dev->bus == &pci_bus_type) {
+		pci_free_consistent(to_pci_dev(dev), size, vaddr, dma_handle);
+		return;
+	}
+#endif
+
+	consistent_free(vaddr);
+}
+
+static inline dma_addr_t
+dma_map_single(struct device *dev, void *ptr, size_t size,
+	       enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+
+	consistent_sync(ptr, size, direction);
+
+	return virt_to_bus(ptr);
+}
+
+/* We do nothing. */
+#define dma_unmap_single(dev, addr, size, dir)	do { } while (0)
+
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page,
+	     unsigned long offset, size_t size,
+	     enum dma_data_direction direction)
+{
+	BUG_ON(direction == DMA_NONE);
+	consistent_sync_page(page, offset, size, direction);
+	return (page - mem_map) * PAGE_SIZE + PCI_DRAM_OFFSET + offset;
+}
+
+/* We do nothing. */
+#define dma_unmap_single(dev, addr, size, dir)	do { } while (0)
+
+static inline int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+	   enum dma_data_direction direction)
+{
+	int i;
+
+	BUG_ON(direction == DMA_NONE);
+
+	for (i = 0; i < nents; i++, sg++) {
+		BUG_ON(!sg->page);
+		consistent_sync_page(sg->page, sg->offset,
+				     sg->length, direction);
+		sg->dma_address = page_to_bus(sg->page) + sg->offset;
+	}
+
+	return nents;
+}
+
+/* We don't do anything here. */
+#define dma_unmap_sg(dev, sg, nents, dir)	do { } while (0)
+
+static inline 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);
+
+	consistent_sync(bus_to_virt(dma_handle), size, 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)
+{
+	BUG_ON(direction == DMA_NONE);
+
+	consistent_sync(bus_to_virt(dma_handle), size, direction);
+}
+
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+		    int nelems, enum dma_data_direction direction)
+{
+	int i;
+
+	BUG_ON(direction == DMA_NONE);
+
+	for (i = 0; i < nelems; i++, sg++)
+		consistent_sync_page(sg->page, sg->offset,
+				     sg->length, direction);
+}
+
+static inline 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);
+
+	for (i = 0; i < nelems; i++, sg++)
+		consistent_sync_page(sg->page, sg->offset,
+				     sg->length, 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)
+{
+	/*
+	 * Each processor family will define its own L1_CACHE_SHIFT,
+	 * L1_CACHE_BYTES wraps to this, so this is always safe.
+	 */
+	return L1_CACHE_BYTES;
+}
+
+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)
+{
+	/* 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_for_device(dev, dma_handle, offset + size, direction);
+}
+
+static inline void dma_cache_sync(void *vaddr, size_t size,
+				  enum dma_data_direction direction)
+{
+	consistent_sync(vaddr, size, (int)direction);
+}
+#endif				/* __ASM_PPC_DMA_MAPPING_H */
diff -Nru a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h
--- a/include/asm-ppc/elf.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-ppc/elf.h	Sat Apr  3 19:38:40 2004
@@ -90,11 +90,17 @@
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	4096
 
-#define ELF_CORE_COPY_REGS(gregs, regs) \
-	memcpy(gregs, regs, \
-	       sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \
-	       sizeof(struct pt_regs): sizeof(elf_gregset_t));
+#define ELF_CORE_COPY_REGS(gregs, regs)				\
+	memcpy((gregs), (regs), sizeof(struct pt_regs));	\
+	memset((char *)(gregs) + sizeof(struct pt_regs), 0,	\
+	       sizeof(elf_gregset_t) - sizeof(struct pt_regs));
 
+#define ELF_CORE_COPY_TASK_REGS(t, elfregs)			\
+	((t)->thread.regs?					\
+	 ({ ELF_CORE_COPY_REGS((elfregs), (t)->thread.regs); 1; }): 0)
+
+extern int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpu);
+#define ELF_CORE_COPY_FPREGS(t, fpu)	dump_task_fpu((t), (fpu))
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this cpu supports.  This could be done in userspace,
diff -Nru a/include/asm-ppc/hawk.h b/include/asm-ppc/hawk.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/hawk.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,32 @@
+/*
+ * include/asm-ppc/hawk.h
+ *
+ * Support functions for MCG Falcon/Raven & HAWK North Bridge & Memory ctlr.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Modified by Randy Vinson (rvinson@mvista.com)
+ *
+ * 2001,2004 (c) 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.
+ */
+
+#ifndef __ASMPPC_HAWK_H
+#define __ASMPPC_HAWK_H
+
+#include <asm/pci-bridge.h>
+#include <asm/hawk_defs.h>
+
+extern int hawk_init(struct pci_controller *hose,
+	      unsigned int ppc_reg_base, unsigned long processor_pci_mem_start,
+	      unsigned long processor_pci_mem_end,
+	      unsigned long processor_pci_io_start,
+	      unsigned long processor_pci_io_end,
+	      unsigned long processor_mpic_base);
+extern unsigned long hawk_get_mem_size(unsigned int smc_base);
+extern int hawk_mpic_init(unsigned int pci_mem_offset);
+
+#endif				/* __ASMPPC_PPLUS_H */
diff -Nru a/include/asm-ppc/hawk_defs.h b/include/asm-ppc/hawk_defs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/hawk_defs.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,76 @@
+/*
+ * include/asm-ppc/hawk_defs.h
+ *
+ * Definitions for Motorola MCG Falcon/Raven & HAWK North Bridge & Memory ctlr.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Modified by Randy Vinson (rvinson@mvista.com)
+ *
+ * 2001-2004 (c) 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.
+ */
+
+#ifndef __ASMPPC_HAWK_DEFS_H
+#define __ASMPPC_HAWK_DEFS_H
+
+#include <asm/pci-bridge.h>
+
+/*
+ * The Falcon/Raven and HAWK have 4 sets of registers:
+ *   1) PPC Registers which define the mappings from PPC bus to PCI bus,
+ *      etc.
+ *   2) PCI Registers which define the mappings from PCI bus to PPC bus and the
+ *      MPIC base address.
+ *   3) MPIC registers
+ *   4) System Memory Controller (SMC) registers.
+ */
+
+#define HAWK_PCI_CONFIG_ADDR_OFF	0x00000cf8
+#define HAWK_PCI_CONFIG_DATA_OFF	0x00000cfc
+
+#define HAWK_MPIC_SIZE			0x00040000U
+#define HAWK_SMC_SIZE			0x00001000U
+
+/*
+ * Define PPC register offsets.
+ */
+#define HAWK_PPC_XSADD0_OFF			0x40
+#define HAWK_PPC_XSOFF0_OFF			0x44
+#define HAWK_PPC_XSADD1_OFF			0x48
+#define HAWK_PPC_XSOFF1_OFF			0x4c
+#define HAWK_PPC_XSADD2_OFF			0x50
+#define HAWK_PPC_XSOFF2_OFF			0x54
+#define HAWK_PPC_XSADD3_OFF			0x58
+#define HAWK_PPC_XSOFF3_OFF			0x5c
+
+/*
+ * Define PCI register offsets.
+ */
+#define HAWK_PCI_PSADD0_OFF			0x80
+#define HAWK_PCI_PSOFF0_OFF			0x84
+#define HAWK_PCI_PSADD1_OFF			0x88
+#define HAWK_PCI_PSOFF1_OFF			0x8c
+#define HAWK_PCI_PSADD2_OFF			0x90
+#define HAWK_PCI_PSOFF2_OFF			0x94
+#define HAWK_PCI_PSADD3_OFF			0x98
+#define HAWK_PCI_PSOFF3_OFF			0x9c
+
+/*
+ * Define the System Memory Controller (SMC) register offsets.
+ */
+#define HAWK_SMC_RAM_A_SIZE_REG_OFF		0x10
+#define HAWK_SMC_RAM_B_SIZE_REG_OFF		0x11
+#define HAWK_SMC_RAM_C_SIZE_REG_OFF		0x12
+#define HAWK_SMC_RAM_D_SIZE_REG_OFF		0x13
+#define HAWK_SMC_RAM_E_SIZE_REG_OFF		0xc0	/* HAWK Only */
+#define HAWK_SMC_RAM_F_SIZE_REG_OFF		0xc1	/* HAWK Only */
+#define HAWK_SMC_RAM_G_SIZE_REG_OFF		0xc2	/* HAWK Only */
+#define HAWK_SMC_RAM_H_SIZE_REG_OFF		0xc3	/* HAWK Only */
+
+#define FALCON_SMC_REG_COUNT			4
+#define HAWK_SMC_REG_COUNT			8
+#endif				/* __ASMPPC_HAWK_DEFS_H */
diff -Nru a/include/asm-ppc/io.h b/include/asm-ppc/io.h
--- a/include/asm-ppc/io.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ppc/io.h	Sat Apr  3 19:38:55 2004
@@ -82,7 +82,6 @@
 #define insl(port, buf, nl)	_insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
 #define outsl(port, buf, nl)	_outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl))
 
-#ifdef CONFIG_PPC_PMAC
 /*
  * On powermacs, we will get a machine check exception if we
  * try to read data from a non-existent I/O port.  Because the
@@ -94,7 +93,7 @@
  * all PPC implementations tested so far.  The twi and isync are
  * needed on the 601 (in fact twi; sync works too), the isync and
  * nop are needed on 604[e|r], and any of twi, sync or isync will
- * work on 603[e], 750, 74x0.
+ * work on 603[e], 750, 74xx.
  * The twi creates an explicit data dependency on the returned
  * value which seems to be needed to make the 601 wait for the
  * load to finish.
@@ -140,27 +139,17 @@
 }
 
 __do_in_asm(inb, "lbzx")
+__do_out_asm(outb, "stbx")
+#ifdef CONFIG_APUS
+__do_in_asm(inw, "lhz%U1%X1")
+__do_in_asm(inl, "lwz%U1%X1")
+__do_out_asm(outl,"stw%U0%X0")
+__do_out_asm(outw, "sth%U0%X0")
+#else
 __do_in_asm(inw, "lhbrx")
 __do_in_asm(inl, "lwbrx")
-__do_out_asm(outb, "stbx")
 __do_out_asm(outw, "sthbrx")
 __do_out_asm(outl, "stwbrx")
-
-#elif defined(CONFIG_APUS)
-#define inb(port)		in_8((u8 *)((port)+_IO_BASE))
-#define outb(val, port)		out_8((u8 *)((port)+_IO_BASE), (val))
-#define inw(port)		in_be16((u16 *)((port)+_IO_BASE))
-#define outw(val, port)		out_be16((u16 *)((port)+_IO_BASE), (val))
-#define inl(port)		in_be32((u32 *)((port)+_IO_BASE))
-#define outl(val, port)		out_be32((u32 *)((port)+_IO_BASE), (val))
-
-#else /* not APUS or PMAC */
-#define inb(port)		in_8((u8 *)((port)+_IO_BASE))
-#define outb(val, port)		out_8((u8 *)((port)+_IO_BASE), (val))
-#define inw(port)		in_le16((u16 *)((port)+_IO_BASE))
-#define outw(val, port)		out_le16((u16 *)((port)+_IO_BASE), (val))
-#define inl(port)		in_le32((u32 *)((port)+_IO_BASE))
-#define outl(val, port)		out_le32((u32 *)((port)+_IO_BASE), (val))
 #endif
 
 #define inb_p(port)		inb((port))
@@ -291,12 +280,19 @@
 
 /*
  * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ *
+ * Read operations have additional twi & isync to make sure the read
+ * is actually performed (i.e. the data has come back) before we start
+ * executing any following instructions.
  */
 extern inline int in_8(volatile unsigned char *addr)
 {
 	int ret;
 
-	__asm__ __volatile__("lbz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+	__asm__ __volatile__(
+		"lbz%U1%X1 %0,%1;\n"
+		"twi 0,%0,0;\n"
+		"isync" : "=r" (ret) : "m" (*addr));
 	return ret;
 }
 
@@ -309,7 +305,9 @@
 {
 	int ret;
 
-	__asm__ __volatile__("lhbrx %0,0,%1; eieio" : "=r" (ret) :
+	__asm__ __volatile__("lhbrx %0,0,%1;\n"
+			     "twi 0,%0,0;\n"
+			     "isync" : "=r" (ret) :
 			      "r" (addr), "m" (*addr));
 	return ret;
 }
@@ -318,7 +316,9 @@
 {
 	int ret;
 
-	__asm__ __volatile__("lhz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+	__asm__ __volatile__("lhz%U1%X1 %0,%1;\n"
+			     "twi 0,%0,0;\n"
+			     "isync" : "=r" (ret) : "m" (*addr));
 	return ret;
 }
 
@@ -337,7 +337,9 @@
 {
 	unsigned ret;
 
-	__asm__ __volatile__("lwbrx %0,0,%1; eieio" : "=r" (ret) :
+	__asm__ __volatile__("lwbrx %0,0,%1;\n"
+			     "twi 0,%0,0;\n"
+			     "isync" : "=r" (ret) :
 			     "r" (addr), "m" (*addr));
 	return ret;
 }
@@ -346,7 +348,9 @@
 {
 	unsigned ret;
 
-	__asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
+	__asm__ __volatile__("lwz%U1%X1 %0,%1;\n"
+			     "twi 0,%0,0;\n"
+			     "isync" : "=r" (ret) : "m" (*addr));
 	return ret;
 }
 
@@ -417,7 +421,7 @@
 #define dma_cache_wback_inv(_start,_size)	do { } while (0)
 
 #define consistent_alloc(gfp, size, handle)	NULL
-#define consistent_free(addr, size)		do { } while (0)
+#define consistent_free(addr)			do { } while (0)
 #define consistent_sync(addr, size, rw)		do { } while (0)
 #define consistent_sync_page(pg, off, sz, rw)	do { } while (0)
 
diff -Nru a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
--- a/include/asm-ppc/machdep.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ppc/machdep.h	Sat Apr  3 19:38:42 2004
@@ -43,6 +43,8 @@
 	long		(*time_init)(void); /* Optional, may be NULL */
 	int		(*set_rtc_time)(unsigned long nowtime);
 	unsigned long	(*get_rtc_time)(void);
+	unsigned char 	(*rtc_read_val)(int addr);
+	void		(*rtc_write_val)(int addr, unsigned char val);
 	void		(*calibrate_decr)(void);
 
 	void		(*heartbeat)(void);
diff -Nru a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
--- a/include/asm-ppc/mmu_context.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-ppc/mmu_context.h	Sat Apr  3 19:38:43 2004
@@ -6,6 +6,7 @@
 #include <asm/atomic.h>
 #include <asm/bitops.h>
 #include <asm/mmu.h>
+#include <asm/cputable.h>
 
 /*
  * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
@@ -155,7 +156,24 @@
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
 			     struct task_struct *tsk)
 {
+#ifdef CONFIG_ALTIVEC
+	asm volatile (
+ BEGIN_FTR_SECTION
+	"dssall;\n"
+#ifndef CONFIG_POWER4
+	 "sync;\n" /* G4 needs a sync here, G5 apparently not */
+#endif
+ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+	 : : );
+#endif /* CONFIG_ALTIVEC */
+
 	tsk->thread.pgdir = next->pgd;
+
+	/* No need to flush userspace segments if the mm doesnt change */
+	if (prev == next)
+		return;
+
+	/* Setup new userspace context */
 	get_mmu_context(next);
 	set_context(next->context, next->pgd);
 }
@@ -166,12 +184,7 @@
  * After we have set current->mm to a new value, this activates
  * the context for the new mm so we see the new mappings.
  */
-static inline void activate_mm(struct mm_struct *active_mm, struct mm_struct *mm)
-{
-	current->thread.pgdir = mm->pgd;
-	get_mmu_context(mm);
-	set_context(mm->context, mm->pgd);
-}
+#define activate_mm(active_mm, mm)   switch_mm(active_mm, mm, current)
 
 extern void mmu_context_init(void);
 
diff -Nru a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
--- a/include/asm-ppc/pci.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-ppc/pci.h	Sat Apr  3 19:38:54 2004
@@ -91,7 +91,7 @@
  * 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,12 +190,22 @@
  * 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)
+{
+	BUG_ON(direction == PCI_DMA_NONE);
+
+	consistent_sync(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);
 
@@ -205,12 +215,25 @@
 /* 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);
+}
+
+static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev,
+					      struct scatterlist *sg,
+					      int nelems, int direction)
 {
 	int i;
 
@@ -237,26 +260,32 @@
  */
 #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 -Nru a/include/asm-ppc/pplus.h b/include/asm-ppc/pplus.h
--- a/include/asm-ppc/pplus.h	Sat Apr  3 19:38:44 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,92 +0,0 @@
-/*
- * include/asm-ppc/pplus.h
- *
- * Definitions for Motorola MCG Falcon/Raven & HAWK North Bridge & Memory ctlr.
- *
- * Author: Mark A. Greer
- *         mgreer@mvista.com
- *
- * 2001 (c) 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.
- */
-
-#ifndef __ASMPPC_PPLUS_H
-#define __ASMPPC_PPLUS_H
-
-#include <asm/pci-bridge.h>
-
-/*
- * The Falcon/Raven and HAWK have 4 sets of registers:
- *   1) PPC Registers which define the mappings from PPC bus to PCI bus,
- *      etc.
- *   2) PCI Registers which define the mappings from PCI bus to PPC bus and the
- *      MPIC base address.
- *   3) MPIC registers
- *   4) System Memory Controller (SMC) registers.
- */
-
-#define	PPLUS_RAVEN_VEND_DEV_ID		0x48011057
-#define	PPLUS_HAWK_VEND_DEV_ID		0x48031057
-
-#define	PPLUS_PCI_CONFIG_ADDR_OFF	0x00000cf8
-#define	PPLUS_PCI_CONFIG_DATA_OFF	0x00000cfc
-
-#define PPLUS_MPIC_SIZE			0x00040000U
-#define PPLUS_SMC_SIZE			0x00001000U
-
-/*
- * Define PPC register offsets.
- */
-#define PPLUS_PPC_XSADD0_OFF			0x40
-#define PPLUS_PPC_XSOFF0_OFF			0x44
-#define PPLUS_PPC_XSADD1_OFF			0x48
-#define PPLUS_PPC_XSOFF1_OFF			0x4c
-#define PPLUS_PPC_XSADD2_OFF			0x50
-#define PPLUS_PPC_XSOFF2_OFF			0x54
-#define PPLUS_PPC_XSADD3_OFF			0x58
-#define PPLUS_PPC_XSOFF3_OFF			0x5c
-
-/*
- * Define PCI register offsets.
- */
-#define PPLUS_PCI_PSADD0_OFF			0x80
-#define PPLUS_PCI_PSOFF0_OFF			0x84
-#define PPLUS_PCI_PSADD1_OFF			0x88
-#define PPLUS_PCI_PSOFF1_OFF			0x8c
-#define PPLUS_PCI_PSADD2_OFF			0x90
-#define PPLUS_PCI_PSOFF2_OFF			0x94
-#define PPLUS_PCI_PSADD3_OFF			0x98
-#define PPLUS_PCI_PSOFF3_OFF			0x9c
-
-/*
- * Define the System Memory Controller (SMC) register offsets.
- */
-#define PPLUS_SMC_RAM_A_SIZE_REG_OFF		0x10
-#define PPLUS_SMC_RAM_B_SIZE_REG_OFF		0x11
-#define PPLUS_SMC_RAM_C_SIZE_REG_OFF		0x12
-#define PPLUS_SMC_RAM_D_SIZE_REG_OFF		0x13
-#define PPLUS_SMC_RAM_E_SIZE_REG_OFF		0xc0	/* HAWK Only */
-#define PPLUS_SMC_RAM_F_SIZE_REG_OFF		0xc1	/* HAWK Only */
-#define PPLUS_SMC_RAM_G_SIZE_REG_OFF		0xc2	/* HAWK Only */
-#define PPLUS_SMC_RAM_H_SIZE_REG_OFF		0xc3	/* HAWK Only */
-
-#define	PPLUS_FALCON_SMC_REG_COUNT		4
-#define	PPLUS_HAWK_SMC_REG_COUNT		8
-
-
-
-int pplus_init(struct pci_controller *hose,
-		 uint ppc_reg_base,
-		 ulong processor_pci_mem_start,
-		 ulong processor_pci_mem_end,
-		 ulong processor_pci_io_start,
-		 ulong processor_pci_io_end,
-		 ulong processor_mpic_base);
-
-unsigned long pplus_get_mem_size(uint smc_base);
-
-int pplus_mpic_init(unsigned int pci_mem_offset);
-
-#endif /* __ASMPPC_PPLUS_H */
diff -Nru a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h
--- a/include/asm-ppc/ptrace.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-ppc/ptrace.h	Sat Apr  3 19:38:43 2004
@@ -49,7 +49,10 @@
 #define instruction_pointer(regs) ((regs)->nip)
 #define user_mode(regs) (((regs)->msr & MSR_PR) != 0)
 
-#define force_successful_syscall_return()   set_thread_flag(TIF_FORCE_NOERROR)
+#define force_successful_syscall_return()   \
+	do { \
+		current_thread_info()->local_flags |= _TIFL_FORCE_NOERROR; \
+	} while(0)
 
 /*
  * We use the least-significant bit of the trap field to indicate
diff -Nru a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h
--- a/include/asm-ppc/reg.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ppc/reg.h	Sat Apr  3 19:38:55 2004
@@ -442,7 +442,9 @@
 #define PVR_440GP_RB	0x40120440
 #define PVR_440GP_RC1	0x40120481
 #define PVR_440GP_RC2	0x40200481
-#define PVR_440GX_RC1	0x51b21850
+#define PVR_440GX_RA	0x51b21850
+#define PVR_440GX_RB	0x51b21851
+#define PVR_440GX_RB1	0x51b21852
 #define PVR_601		0x00010000
 #define PVR_602		0x00050000
 #define PVR_603		0x00030000
diff -Nru a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
--- a/include/asm-ppc/reg_booke.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-ppc/reg_booke.h	Sat Apr  3 19:38:54 2004
@@ -55,8 +55,6 @@
 
 /* Special Purpose Registers (SPRNs)*/
 #define SPRN_DECAR	0x036	/* Decrementer Auto Reload Register */
-#define SPRN_CSRR0	0x03A	/* Critical Save and Restore Register 0 */
-#define SPRN_CSRR1	0x03B	/* Critical Save and Restore Register 1 */
 #define SPRN_IVPR	0x03F	/* Interrupt Vector Prefix Register */
 #define SPRN_USPRG0	0x100	/* User Special Purpose Register General 0 */
 #define SPRN_SPRG4R	0x104	/* Special Purpose Register General 4 Read */
@@ -108,6 +106,8 @@
  */
 #ifdef CONFIG_BOOKE
 #define SPRN_PID	0x030	/* Process ID */
+#define SPRN_CSRR0	0x03A	/* Critical Save and Restore Register 0 */
+#define SPRN_CSRR1	0x03B	/* Critical Save and Restore Register 1 */
 #define SPRN_DEAR	0x03D	/* Data Error Address Register */
 #define SPRN_ESR	0x03E	/* Exception Syndrome Register */
 #define SPRN_PIR	0x11E	/* Processor Identification Register */
diff -Nru a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
--- a/include/asm-ppc/serial.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-ppc/serial.h	Sat Apr  3 19:38:56 2004
@@ -27,7 +27,7 @@
 #elif defined(CONFIG_SANDPOINT)
 #include <platforms/sandpoint.h>
 #elif defined(CONFIG_SPRUCE)
-#include <platforms/spruce_serial.h>
+#include <platforms/spruce.h>
 #elif defined(CONFIG_4xx)
 #include <asm/ibm4xx.h>
 #else
diff -Nru a/include/asm-ppc/thread_info.h b/include/asm-ppc/thread_info.h
--- a/include/asm-ppc/thread_info.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ppc/thread_info.h	Sat Apr  3 19:38:42 2004
@@ -18,6 +18,7 @@
 	struct task_struct	*task;		/* main task structure */
 	struct exec_domain	*exec_domain;	/* execution domain */
 	unsigned long		flags;		/* low level flags */
+	unsigned long		local_flags;	/* non-racy flags */
 	int			cpu;		/* cpu we're on */
 	int			preempt_count;
 	struct restart_block	restart_block;
@@ -28,6 +29,7 @@
 	.task =		&tsk,			\
 	.exec_domain =	&default_exec_domain,	\
 	.flags =	0,			\
+	.local_flags =  0,			\
 	.cpu =		0,			\
 	.preempt_count = 1,			\
 	.restart_block = {			\
@@ -69,8 +71,9 @@
 #define TI_TASK		0
 #define TI_EXECDOMAIN	4
 #define TI_FLAGS	8
-#define TI_CPU		12
-#define TI_PREEMPT	16
+#define TI_LOCAL_FLAGS	12
+#define TI_CPU		16
+#define TI_PREEMPT	20
 
 #define PREEMPT_ACTIVE		0x4000000
 
@@ -83,16 +86,22 @@
 #define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 #define TIF_POLLING_NRFLAG	4	/* true if poll_idle() is polling
 					   TIF_NEED_RESCHED */
-#define TIF_FORCE_NOERROR	5	/* don't return error from current
-					   syscall even if result < 0 */
-
 /* as above, but as bit values */
 #define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
 #define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
-#define _TIF_FORCE_NOERROR	(1<<TIF_FORCE_NOERROR)
+
+/*
+ * Non racy (local) flags bit numbers
+ */
+#define TIFL_FORCE_NOERROR	0	/* don't return error from current
+					   syscall even if result < 0 */
+
+/* as above, but as bit values */
+#define _TIFL_FORCE_NOERROR	(1<<TIFL_FORCE_NOERROR)
+
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/asm-ppc/todc.h b/include/asm-ppc/todc.h
--- a/include/asm-ppc/todc.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-ppc/todc.h	Sat Apr  3 19:38:54 2004
@@ -29,9 +29,9 @@
 	 * Following are the addresses of the AS0, AS1, and DATA registers
 	 * of these chips.  Note that these are board-specific.
 	 */
-	unsigned char *nvram_as0;
-	unsigned char *nvram_as1;
-	unsigned char *nvram_data;
+	unsigned int nvram_as0;
+	unsigned int nvram_as1;
+	unsigned int nvram_data;
 
 	/*
 	 * Define bits to stop external set of regs from changing so
@@ -46,6 +46,9 @@
 	 */
 	int as0_bits;
 
+	int nvram_size;	/* Size of NVRAM on chip */
+	int sw_flags;	/* Software control flags */
+
 	/* Following are the register offsets for the particular chip */
 	int year;
 	int month;
@@ -64,6 +67,14 @@
 	int alarm_seconds;
 	int century;
 	int flags;
+
+	/*
+	 * Some RTC chips have their NVRAM buried behind a addr/data pair of
+	 * regs on the first level/clock registers.  The following fields
+	 * are the addresses for those addr/data regs.
+	 */
+	int nvram_addr_reg;
+	int nvram_data_reg;
 } todc_info_t;
 
 /*
@@ -86,7 +97,8 @@
 #define TODC_TYPE_DS1643		9	/* Dallas DS1643 RTC */
 #define TODC_TYPE_PC97307		10	/* PC97307 internal RTC */
 #define TODC_TYPE_DS1557		11	/* Dallas DS1557 RTC */
-#define	TODC_TYPE_MC146818		100	/* Leave room for more m48txx's */
+#define TODC_TYPE_DS17285		12	/* Dallas DS17285 RTC */
+#define	TODC_TYPE_MC146818		100	/* Leave room for m48txx's */
 
 /*
  * Bit to clear/set to enable reads/writes to the chip
@@ -98,9 +110,18 @@
 #define	TODC_DS1501_CNTL_B_TE		0x80
 
 /*
+ * Define flag bits used by todc routines.
+ */
+#define	TODC_FLAG_2_LEVEL_NVRAM		0x00000001
+
+/*
  * Define the values for the various RTC's that should to into the todc_info
  * table.
+ * Note: The XXX_NVRAM_SIZE, XXX_NVRAM_ADDR_REG, and XXX_NVRAM_DATA_REG only
+ * matter if XXX_SW_FLAGS has TODC_FLAG_2_LEVEL_NVRAM set.
  */
+#define	TODC_TYPE_MK48T35_NVRAM_SIZE		0x7ff8
+#define	TODC_TYPE_MK48T35_SW_FLAGS		0
 #define	TODC_TYPE_MK48T35_YEAR			0x7fff
 #define	TODC_TYPE_MK48T35_MONTH			0x7ffe
 #define	TODC_TYPE_MK48T35_DOM			0x7ffd	/* Day of Month */
@@ -118,7 +139,11 @@
 #define	TODC_TYPE_MK48T35_ALARM_SECONDS		0x0000
 #define	TODC_TYPE_MK48T35_CENTURY		0x0000
 #define	TODC_TYPE_MK48T35_FLAGS			0x0000
+#define	TODC_TYPE_MK48T35_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T35_NVRAM_DATA_REG	0
 
+#define	TODC_TYPE_MK48T37_NVRAM_SIZE		0x7ff0
+#define	TODC_TYPE_MK48T37_SW_FLAGS		0
 #define	TODC_TYPE_MK48T37_YEAR			0x7fff
 #define	TODC_TYPE_MK48T37_MONTH			0x7ffe
 #define	TODC_TYPE_MK48T37_DOM			0x7ffd	/* Day of Month */
@@ -136,7 +161,11 @@
 #define	TODC_TYPE_MK48T37_ALARM_SECONDS		0x7ff2
 #define	TODC_TYPE_MK48T37_CENTURY		0x7ff1
 #define	TODC_TYPE_MK48T37_FLAGS			0x7ff0
+#define	TODC_TYPE_MK48T37_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T37_NVRAM_DATA_REG	0
 
+#define	TODC_TYPE_MK48T59_NVRAM_SIZE		0x1ff0
+#define	TODC_TYPE_MK48T59_SW_FLAGS		0
 #define	TODC_TYPE_MK48T59_YEAR			0x1fff
 #define	TODC_TYPE_MK48T59_MONTH			0x1ffe
 #define	TODC_TYPE_MK48T59_DOM			0x1ffd	/* Day of Month */
@@ -154,25 +183,33 @@
 #define	TODC_TYPE_MK48T59_ALARM_SECONDS		0x1fff
 #define	TODC_TYPE_MK48T59_CENTURY		0x1fff
 #define	TODC_TYPE_MK48T59_FLAGS			0x1fff
+#define	TODC_TYPE_MK48T59_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MK48T59_NVRAM_DATA_REG	0
 
-#define	TODC_TYPE_DS1501_YEAR			0x06
-#define	TODC_TYPE_DS1501_MONTH			0x05
-#define	TODC_TYPE_DS1501_DOM			0x04	/* Day of Month */
-#define	TODC_TYPE_DS1501_DOW			0x03	/* Day of Week */
-#define	TODC_TYPE_DS1501_HOURS			0x02
-#define	TODC_TYPE_DS1501_MINUTES		0x01
-#define	TODC_TYPE_DS1501_SECONDS		0x00
-#define	TODC_TYPE_DS1501_CNTL_B			0x0f
-#define	TODC_TYPE_DS1501_CNTL_A			0x0f
-#define	TODC_TYPE_DS1501_WATCHDOG		0xff
-#define	TODC_TYPE_DS1501_INTERRUPTS		0xff
-#define	TODC_TYPE_DS1501_ALARM_DATE		0x0b
-#define	TODC_TYPE_DS1501_ALARM_HOUR		0x0a
-#define	TODC_TYPE_DS1501_ALARM_MINUTES		0x09
-#define	TODC_TYPE_DS1501_ALARM_SECONDS		0x08
-#define	TODC_TYPE_DS1501_CENTURY		0x07
-#define	TODC_TYPE_DS1501_FLAGS			0xff
+#define	TODC_TYPE_DS1501_NVRAM_SIZE	0x100
+#define	TODC_TYPE_DS1501_SW_FLAGS	TODC_FLAG_2_LEVEL_NVRAM
+#define	TODC_TYPE_DS1501_YEAR		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x06)
+#define	TODC_TYPE_DS1501_MONTH		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x05)
+#define	TODC_TYPE_DS1501_DOM		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x04)
+#define	TODC_TYPE_DS1501_DOW		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x03)
+#define	TODC_TYPE_DS1501_HOURS		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x02)
+#define	TODC_TYPE_DS1501_MINUTES	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x01)
+#define	TODC_TYPE_DS1501_SECONDS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x00)
+#define	TODC_TYPE_DS1501_CNTL_B		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f)
+#define	TODC_TYPE_DS1501_CNTL_A		(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0f)
+#define	TODC_TYPE_DS1501_WATCHDOG	(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_INTERRUPTS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_ALARM_DATE	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0b)
+#define	TODC_TYPE_DS1501_ALARM_HOUR	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x0a)
+#define	TODC_TYPE_DS1501_ALARM_MINUTES	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x09)
+#define	TODC_TYPE_DS1501_ALARM_SECONDS	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x08)
+#define	TODC_TYPE_DS1501_CENTURY	(TODC_TYPE_DS1501_NVRAM_SIZE + 0x07)
+#define	TODC_TYPE_DS1501_FLAGS		(TODC_TYPE_DS1501_NVRAM_SIZE + 0xff)
+#define	TODC_TYPE_DS1501_NVRAM_ADDR_REG	0x10
+#define	TODC_TYPE_DS1501_NVRAM_DATA_REG	0x13
 
+#define	TODC_TYPE_DS1557_NVRAM_SIZE		0x7fff0
+#define	TODC_TYPE_DS1557_SW_FLAGS		0
 #define	TODC_TYPE_DS1557_YEAR			0x7ffff
 #define	TODC_TYPE_DS1557_MONTH			0x7fffe
 #define	TODC_TYPE_DS1557_DOM			0x7fffd	/* Day of Month */
@@ -190,7 +227,11 @@
 #define	TODC_TYPE_DS1557_ALARM_SECONDS		0x7fff2
 #define	TODC_TYPE_DS1557_CENTURY		0x7fff8
 #define	TODC_TYPE_DS1557_FLAGS			0x7fff0
+#define	TODC_TYPE_DS1557_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1557_NVRAM_DATA_REG		0
 
+#define	TODC_TYPE_DS1643_NVRAM_SIZE		0x1ff8
+#define	TODC_TYPE_DS1643_SW_FLAGS		0
 #define	TODC_TYPE_DS1643_YEAR			0x1fff
 #define	TODC_TYPE_DS1643_MONTH			0x1ffe
 #define	TODC_TYPE_DS1643_DOM			0x1ffd	/* Day of Month */
@@ -208,7 +249,11 @@
 #define	TODC_TYPE_DS1643_ALARM_SECONDS		0x1fff
 #define	TODC_TYPE_DS1643_CENTURY		0x1ff8
 #define	TODC_TYPE_DS1643_FLAGS			0x1fff
+#define	TODC_TYPE_DS1643_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1643_NVRAM_DATA_REG		0
 
+#define	TODC_TYPE_DS1693_NVRAM_SIZE		0 /* Not handled yet */
+#define	TODC_TYPE_DS1693_SW_FLAGS		0
 #define	TODC_TYPE_DS1693_YEAR			0x09
 #define	TODC_TYPE_DS1693_MONTH			0x08
 #define	TODC_TYPE_DS1693_DOM			0x07	/* Day of Month */
@@ -226,7 +271,11 @@
 #define	TODC_TYPE_DS1693_ALARM_SECONDS		0x01
 #define	TODC_TYPE_DS1693_CENTURY		0x48
 #define	TODC_TYPE_DS1693_FLAGS			0xff
+#define	TODC_TYPE_DS1693_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1693_NVRAM_DATA_REG		0
 
+#define	TODC_TYPE_DS1743_NVRAM_SIZE		0x1ff8
+#define	TODC_TYPE_DS1743_SW_FLAGS		0
 #define	TODC_TYPE_DS1743_YEAR			0x1fff
 #define	TODC_TYPE_DS1743_MONTH			0x1ffe
 #define	TODC_TYPE_DS1743_DOM			0x1ffd	/* Day of Month */
@@ -244,7 +293,11 @@
 #define	TODC_TYPE_DS1743_ALARM_SECONDS		0x1fff
 #define	TODC_TYPE_DS1743_CENTURY		0x1ff8
 #define	TODC_TYPE_DS1743_FLAGS			0x1fff
+#define	TODC_TYPE_DS1743_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1743_NVRAM_DATA_REG		0
 
+#define	TODC_TYPE_DS1746_NVRAM_SIZE		0x1fff8
+#define	TODC_TYPE_DS1746_SW_FLAGS		0
 #define	TODC_TYPE_DS1746_YEAR			0x1ffff
 #define	TODC_TYPE_DS1746_MONTH			0x1fffe
 #define	TODC_TYPE_DS1746_DOM			0x1fffd	/* Day of Month */
@@ -262,16 +315,20 @@
 #define	TODC_TYPE_DS1746_ALARM_SECONDS		0x00000
 #define	TODC_TYPE_DS1746_CENTURY		0x00000
 #define	TODC_TYPE_DS1746_FLAGS			0x00000
+#define	TODC_TYPE_DS1746_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1746_NVRAM_DATA_REG		0
 
-#define	TODC_TYPE_DS1747_YEAR			0x1ffff
-#define	TODC_TYPE_DS1747_MONTH			0x1fffe
-#define	TODC_TYPE_DS1747_DOM			0x1fffd	/* Day of Month */
-#define	TODC_TYPE_DS1747_DOW			0x1fffc	/* Day of Week */
-#define	TODC_TYPE_DS1747_HOURS			0x1fffb
-#define	TODC_TYPE_DS1747_MINUTES		0x1fffa
-#define	TODC_TYPE_DS1747_SECONDS		0x1fff9
-#define	TODC_TYPE_DS1747_CNTL_B			0x1fff9
-#define	TODC_TYPE_DS1747_CNTL_A			0x1fff8	/* control_a R/W regs */
+#define	TODC_TYPE_DS1747_NVRAM_SIZE		0x7fff8
+#define	TODC_TYPE_DS1747_SW_FLAGS		0
+#define	TODC_TYPE_DS1747_YEAR			0x7ffff
+#define	TODC_TYPE_DS1747_MONTH			0x7fffe
+#define	TODC_TYPE_DS1747_DOM			0x7fffd	/* Day of Month */
+#define	TODC_TYPE_DS1747_DOW			0x7fffc	/* Day of Week */
+#define	TODC_TYPE_DS1747_HOURS			0x7fffb
+#define	TODC_TYPE_DS1747_MINUTES		0x7fffa
+#define	TODC_TYPE_DS1747_SECONDS		0x7fff9
+#define	TODC_TYPE_DS1747_CNTL_B			0x7fff9
+#define	TODC_TYPE_DS1747_CNTL_A			0x7fff8	/* control_a R/W regs */
 #define	TODC_TYPE_DS1747_WATCHDOG		0x00000
 #define	TODC_TYPE_DS1747_INTERRUPTS		0x00000
 #define	TODC_TYPE_DS1747_ALARM_DATE		0x00000
@@ -280,7 +337,35 @@
 #define	TODC_TYPE_DS1747_ALARM_SECONDS		0x00000
 #define	TODC_TYPE_DS1747_CENTURY		0x00000
 #define	TODC_TYPE_DS1747_FLAGS			0x00000
+#define	TODC_TYPE_DS1747_NVRAM_ADDR_REG		0
+#define	TODC_TYPE_DS1747_NVRAM_DATA_REG		0
 
+#define TODC_TYPE_DS17285_NVRAM_SIZE		(0x1000-0x80)    /* 4Kx8 NVRAM (minus RTC regs) */
+#define TODC_TYPE_DS17285_SW_FLAGS		TODC_FLAG_2_LEVEL_NVRAM
+#define TODC_TYPE_DS17285_SECONDS		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x00)
+#define TODC_TYPE_DS17285_ALARM_SECONDS		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x01)
+#define TODC_TYPE_DS17285_MINUTES		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x02)
+#define TODC_TYPE_DS17285_ALARM_MINUTES		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x03)
+#define TODC_TYPE_DS17285_HOURS			(TODC_TYPE_DS17285_NVRAM_SIZE + 0x04)
+#define TODC_TYPE_DS17285_ALARM_HOUR		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x05)
+#define TODC_TYPE_DS17285_DOW			(TODC_TYPE_DS17285_NVRAM_SIZE + 0x06)
+#define TODC_TYPE_DS17285_DOM			(TODC_TYPE_DS17285_NVRAM_SIZE + 0x07)
+#define TODC_TYPE_DS17285_MONTH			(TODC_TYPE_DS17285_NVRAM_SIZE + 0x08)
+#define TODC_TYPE_DS17285_YEAR			(TODC_TYPE_DS17285_NVRAM_SIZE + 0x09)
+#define TODC_TYPE_DS17285_CNTL_A		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x0A)
+#define TODC_TYPE_DS17285_CNTL_B		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x0B)
+#define TODC_TYPE_DS17285_CNTL_C		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x0C)
+#define TODC_TYPE_DS17285_CNTL_D		(TODC_TYPE_DS17285_NVRAM_SIZE + 0x0D)
+#define TODC_TYPE_DS17285_WATCHDOG		0
+#define TODC_TYPE_DS17285_INTERRUPTS		0
+#define TODC_TYPE_DS17285_ALARM_DATE		0
+#define TODC_TYPE_DS17285_CENTURY		0
+#define TODC_TYPE_DS17285_FLAGS			0
+#define TODC_TYPE_DS17285_NVRAM_ADDR_REG	0x50
+#define TODC_TYPE_DS17285_NVRAM_DATA_REG	0x53
+ 
+#define	TODC_TYPE_MC146818_NVRAM_SIZE		0	/* XXXX */
+#define	TODC_TYPE_MC146818_SW_FLAGS		0
 #define	TODC_TYPE_MC146818_YEAR			0x09
 #define	TODC_TYPE_MC146818_MONTH		0x08
 #define	TODC_TYPE_MC146818_DOM			0x07	/* Day of Month */
@@ -298,7 +383,11 @@
 #define	TODC_TYPE_MC146818_ALARM_SECONDS	0x01
 #define	TODC_TYPE_MC146818_CENTURY		0xff
 #define	TODC_TYPE_MC146818_FLAGS		0xff
-
+#define	TODC_TYPE_MC146818_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_MC146818_NVRAM_DATA_REG	0
+  
+#define	TODC_TYPE_PC97307_NVRAM_SIZE		0	/* No NVRAM? */
+#define	TODC_TYPE_PC97307_SW_FLAGS		0
 #define	TODC_TYPE_PC97307_YEAR			0x09
 #define	TODC_TYPE_PC97307_MONTH			0x08
 #define	TODC_TYPE_PC97307_DOM			0x07	/* Day of Month */
@@ -316,6 +405,8 @@
 #define	TODC_TYPE_PC97307_ALARM_SECONDS		0x01
 #define	TODC_TYPE_PC97307_CENTURY		0xff
 #define	TODC_TYPE_PC97307_FLAGS			0xff
+#define	TODC_TYPE_PC97307_NVRAM_ADDR_REG	0
+#define	TODC_TYPE_PC97307_NVRAM_DATA_REG	0
 
 /*
  * Define macros to allocate and init the todc_info_t table that will
@@ -328,29 +419,35 @@
 #define	TODC_INIT(clock_type, as0, as1, data, bits) {			\
 	todc_info->rtc_type = clock_type;				\
 									\
-	todc_info->nvram_as0  = (unsigned char *)(as0);			\
-	todc_info->nvram_as1  = (unsigned char *)(as1);			\
-	todc_info->nvram_data = (unsigned char *)(data);			\
+	todc_info->nvram_as0  = (unsigned int)(as0);			\
+	todc_info->nvram_as1  = (unsigned int)(as1);			\
+	todc_info->nvram_data = (unsigned int)(data);			\
 									\
 	todc_info->as0_bits = (bits);					\
 									\
-	todc_info->year          = clock_type ##_YEAR;			\
-	todc_info->month         = clock_type ##_MONTH;			\
-	todc_info->day_of_month  = clock_type ##_DOM;			\
-	todc_info->day_of_week   = clock_type ##_DOW;			\
-	todc_info->hours         = clock_type ##_HOURS;			\
-	todc_info->minutes       = clock_type ##_MINUTES;		\
-	todc_info->seconds       = clock_type ##_SECONDS;		\
-	todc_info->control_b     = clock_type ##_CNTL_B;		\
-	todc_info->control_a     = clock_type ##_CNTL_A;		\
-	todc_info->watchdog      = clock_type ##_WATCHDOG;		\
-	todc_info->interrupts    = clock_type ##_INTERRUPTS;		\
-	todc_info->alarm_date    = clock_type ##_ALARM_DATE;		\
-	todc_info->alarm_hour    = clock_type ##_ALARM_HOUR;		\
-	todc_info->alarm_minutes = clock_type ##_ALARM_MINUTES;		\
-	todc_info->alarm_seconds = clock_type ##_ALARM_SECONDS;		\
-	todc_info->century       = clock_type ##_CENTURY;		\
-	todc_info->flags         = clock_type ##_FLAGS;			\
+	todc_info->nvram_size     = clock_type ##_NVRAM_SIZE;		\
+	todc_info->sw_flags       = clock_type ##_SW_FLAGS;		\
+									\
+	todc_info->year           = clock_type ##_YEAR;			\
+	todc_info->month          = clock_type ##_MONTH;		\
+	todc_info->day_of_month   = clock_type ##_DOM;			\
+	todc_info->day_of_week    = clock_type ##_DOW;			\
+	todc_info->hours          = clock_type ##_HOURS;		\
+	todc_info->minutes        = clock_type ##_MINUTES;		\
+	todc_info->seconds        = clock_type ##_SECONDS;		\
+	todc_info->control_b      = clock_type ##_CNTL_B;		\
+	todc_info->control_a      = clock_type ##_CNTL_A;		\
+	todc_info->watchdog       = clock_type ##_WATCHDOG;		\
+	todc_info->interrupts     = clock_type ##_INTERRUPTS;		\
+	todc_info->alarm_date     = clock_type ##_ALARM_DATE;		\
+	todc_info->alarm_hour     = clock_type ##_ALARM_HOUR;		\
+	todc_info->alarm_minutes  = clock_type ##_ALARM_MINUTES;	\
+	todc_info->alarm_seconds  = clock_type ##_ALARM_SECONDS;	\
+	todc_info->century        = clock_type ##_CENTURY;		\
+	todc_info->flags          = clock_type ##_FLAGS;		\
+									\
+	todc_info->nvram_addr_reg = clock_type ##_NVRAM_ADDR_REG;	\
+	todc_info->nvram_data_reg = clock_type ##_NVRAM_DATA_REG;	\
 }
 
 extern todc_info_t *todc_info;
diff -Nru a/include/asm-ppc/types.h b/include/asm-ppc/types.h
--- a/include/asm-ppc/types.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ppc/types.h	Sat Apr  3 19:38:55 2004
@@ -37,6 +37,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/config.h>
+
 typedef signed char s8;
 typedef unsigned char u8;
 
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-ppc/unistd.h	Sat Apr  3 19:38:41 2004
@@ -415,10 +415,10 @@
 int sys_pipe(int __user *fildes);
 int sys_ptrace(long request, long pid, long addr, long data);
 struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
-				const struct sigaction __user *act,
-				struct sigaction __user *oact,
-				size_t sigsetsize);
+long sys_rt_sigaction(int sig,
+		      const struct sigaction __user *act,
+		      struct sigaction __user *oact,
+		      size_t sigsetsize);
 
 #endif /* __KERNEL_SYSCALLS__ */
 
diff -Nru a/include/asm-ppc64/abs_addr.h b/include/asm-ppc64/abs_addr.h
--- a/include/asm-ppc64/abs_addr.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ppc64/abs_addr.h	Sat Apr  3 19:38:55 2004
@@ -71,26 +71,22 @@
 	return PTRRELOC(_msChunks->abs)[pchunk];
 }
 
-
-static inline unsigned long
-phys_to_absolute(unsigned long pa)
-{
-	return chunk_to_addr(abs_chunk(addr_to_chunk(pa))) + chunk_offset(pa);
-}
+/* A macro so it can take pointers or unsigned long. */
+#define phys_to_abs(pa)						     \
+	({ unsigned long _pa = (unsigned long)(pa);			     \
+	   chunk_to_addr(abs_chunk(addr_to_chunk(_pa))) + chunk_offset(_pa); \
+	})
 
 static inline unsigned long
 physRpn_to_absRpn(unsigned long rpn)
 {
 	unsigned long pa = rpn << PAGE_SHIFT;
-	unsigned long aa = phys_to_absolute(pa);
+	unsigned long aa = phys_to_abs(pa);
 	return (aa >> PAGE_SHIFT);
 }
 
-static inline unsigned long
-absolute_to_phys(unsigned long aa)
-{
-	return lmb_abs_to_phys(aa);
-}
+/* A macro so it can take pointers or unsigned long. */
+#define abs_to_phys(aa) lmb_abs_to_phys((unsigned long)(aa))
 
 #else  /* !CONFIG_MSCHUNKS */
 
@@ -99,23 +95,14 @@
 #define chunk_offset(addr) (0)
 #define abs_chunk(pchunk) (pchunk)
 
-#define phys_to_absolute(pa) (pa)
+#define phys_to_abs(pa) (pa)
 #define physRpn_to_absRpn(rpn) (rpn)
-#define absolute_to_phys(aa) (aa)
+#define abs_to_phys(aa) (aa)
 
 #endif /* !CONFIG_MSCHUNKS */
 
-
-static inline unsigned long
-virt_to_absolute(unsigned long ea)
-{
-	return phys_to_absolute(__pa(ea));
-}
-
-static inline unsigned long
-absolute_to_virt(unsigned long aa)
-{
-	return (unsigned long)__va(absolute_to_phys(aa));
-}
+/* Convenience macros */
+#define virt_to_abs(va) phys_to_abs(__pa(va))
+#define abs_to_virt(aa) __va(abs_to_phys(aa))
 
 #endif /* _ABS_ADDR_H */
diff -Nru a/include/asm-ppc64/dma-mapping.h b/include/asm-ppc64/dma-mapping.h
--- a/include/asm-ppc64/dma-mapping.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-ppc64/dma-mapping.h	Sat Apr  3 19:38:56 2004
@@ -1 +1,82 @@
-#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>
+
+#define DMA_ERROR_CODE		(~(dma_addr_t)0x0)
+
+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();
+}
+
+static inline int dma_mapping_error(dma_addr_t dma_addr)
+{
+	return (dma_addr == DMA_ERROR_CODE);
+}
+
+#endif	/* _ASM_DMA_MAPPING_H */
diff -Nru a/include/asm-ppc64/eeh.h b/include/asm-ppc64/eeh.h
--- a/include/asm-ppc64/eeh.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ppc64/eeh.h	Sat Apr  3 19:38:55 2004
@@ -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 @@
  * 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 @@
 #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 @@
  * 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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_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 @@
 	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 @@
 	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 @@
 	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 @@
 		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 -Nru a/include/asm-ppc64/hvcall.h b/include/asm-ppc64/hvcall.h
--- a/include/asm-ppc64/hvcall.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-ppc64/hvcall.h	Sat Apr  3 19:38:40 2004
@@ -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 -Nru a/include/asm-ppc64/iSeries/HvCallEvent.h b/include/asm-ppc64/iSeries/HvCallEvent.h
--- a/include/asm-ppc64/iSeries/HvCallEvent.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-ppc64/iSeries/HvCallEvent.h	Sat Apr  3 19:38:54 2004
@@ -100,7 +100,7 @@
 {
 	u64 abs_addr;
 
-	abs_addr = virt_to_absolute((unsigned long)eventStackAddr);
+	abs_addr = virt_to_abs(eventStackAddr);
 	HvCall3(HvCallEventSetLpEventStack, queueIndex, abs_addr,
 			eventStackSize);
 	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
@@ -123,7 +123,7 @@
 	printk("HvCallEvent_signalLpEvent: *event = %016lx\n ",
 			(unsigned long)event);
 #endif
-	abs_addr = virt_to_absolute((unsigned long)event);
+	abs_addr = virt_to_abs(event);
 	retVal = (HvLpEvent_Rc)HvCall1(HvCallEventSignalLpEvent, abs_addr);
 	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 	return retVal;
@@ -164,7 +164,7 @@
 	u64 abs_addr;
 	HvLpEvent_Rc retVal;
 
-	abs_addr = virt_to_absolute((unsigned long)event);
+	abs_addr = virt_to_abs(event);
 	retVal = (HvLpEvent_Rc)HvCall1(HvCallEventAckLpEvent, abs_addr);
 	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 	return retVal;
@@ -175,7 +175,7 @@
 	u64 abs_addr;
 	HvLpEvent_Rc retVal;
 
-	abs_addr = virt_to_absolute((unsigned long)event);
+	abs_addr = virt_to_abs(event);
 	retVal = (HvLpEvent_Rc)HvCall1(HvCallEventCancelLpEvent, abs_addr);
 	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
 	return retVal;
@@ -286,7 +286,7 @@
 	u64 abs_addr;
 	HvLpDma_Rc retVal;
 
-	abs_addr = virt_to_absolute((unsigned long)local);
+	abs_addr = virt_to_abs(local);
 	retVal = (HvLpDma_Rc)HvCall4(HvCallEventDmaToSp, abs_addr, remote,
 			length, dir);
 	// getPaca()->adjustHmtForNoOfSpinLocksHeld();
diff -Nru a/include/asm-ppc64/iSeries/iSeries_pci.h b/include/asm-ppc64/iSeries/iSeries_pci.h
--- a/include/asm-ppc64/iSeries/iSeries_pci.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-ppc64/iSeries/iSeries_pci.h	Sat Apr  3 19:38:41 2004
@@ -31,6 +31,7 @@
 /************************************************************************/
 
 #include <asm/iSeries/HvCallPci.h>
+#include <asm/abs_addr.h>
 
 struct pci_dev;				/* For Forward Reference        */
 struct iSeries_Device_Node;
@@ -71,7 +72,7 @@
 /* Converts Virtual Address to Real Address for Hypervisor calls        */
 /************************************************************************/
 
-#define REALADDR(virtaddr)  (0x8000000000000000 | (virt_to_absolute((u64)virtaddr) ))
+#define ISERIES_HV_ADDR(virtaddr)  (0x8000000000000000 | virt_to_abs(virtaddr))
 
 /************************************************************************/
 /* iSeries Device Information                                           */
diff -Nru a/include/asm-ppc64/iSeries/iSeries_proc.h b/include/asm-ppc64/iSeries/iSeries_proc.h
--- a/include/asm-ppc64/iSeries/iSeries_proc.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-ppc64/iSeries/iSeries_proc.h	Sat Apr  3 19:38:45 2004
@@ -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 -Nru a/include/asm-ppc64/iSeries/mf.h b/include/asm-ppc64/iSeries/mf.h
--- a/include/asm-ppc64/iSeries/mf.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ppc64/iSeries/mf.h	Sat Apr  3 19:38:42 2004
@@ -67,6 +67,4 @@
 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 -Nru a/include/asm-ppc64/iSeries/vio.h b/include/asm-ppc64/iSeries/vio.h
--- a/include/asm-ppc64/iSeries/vio.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-ppc64/iSeries/vio.h	Sat Apr  3 19:38:56 2004
@@ -70,11 +70,6 @@
 extern HvLpIndex viopath_hostLp;
 extern HvLpIndex viopath_ourLp;
 
-#define VIO_MESSAGE "iSeries virtual I/O: "
-#define KERN_DEBUG_VIO KERN_DEBUG VIO_MESSAGE
-#define KERN_INFO_VIO KERN_INFO VIO_MESSAGE
-#define KERN_WARNING_VIO KERN_WARNING VIO_MESSAGE
-
 #define VIOCHAR_MAX_DATA 200
 
 #define VIOMAJOR_SUBTYPE_MASK 0xff00
@@ -84,11 +79,11 @@
 #define VIOVERSION            0x0101
 
 /*
-This is the general structure for VIO errors; each module should have a table
-of them, and each table should be terminated by an entry of { 0, 0, NULL }.
-Then, to find a specific error message, a module should pass its local table
-and the return code.
-*/
+ * This is the general structure for VIO errors; each module should have
+ * a table of them, and each table should be terminated by an entry of
+ * { 0, 0, NULL }.  Then, to find a specific error message, a module
+ * should pass its local table and the return code.
+ */
 struct vio_error_entry {
 	u16 rc;
 	int errno;
diff -Nru a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h
--- a/include/asm-ppc64/io.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-ppc64/io.h	Sat Apr  3 19:38:56 2004
@@ -27,8 +27,6 @@
 #define SIO_CONFIG_RD	0x399
 
 #define SLOW_DOWN_IO
-/* Define this if you want to see virt_to_* messages */
-#undef __IO_DEBUG
 
 extern unsigned long isa_io_base;
 extern unsigned long pci_io_base;
@@ -58,6 +56,13 @@
 #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 +95,16 @@
  * 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 +139,7 @@
  * 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))
 
 
@@ -140,40 +147,61 @@
 
 
 #ifdef __KERNEL__
-/*
- * Map in an area of physical address space, for accessing
- * I/O devices etc.
- */
 extern int __ioremap_explicit(unsigned long p_addr, unsigned long v_addr,
 		     	      unsigned long size, unsigned long flags);
 extern void *__ioremap(unsigned long address, unsigned long size,
 		       unsigned long flags);
+
+/**
+ * ioremap     -   map bus memory into CPU space
+ * @address:   bus address of the memory
+ * @size:      size of the resource to map
+ *
+ * ioremap performs a platform specific sequence of operations to
+ * make bus memory CPU accessible via the readb/readw/readl/writeb/
+ * writew/writel functions and the other mmio helpers. The returned
+ * address is not guaranteed to be usable directly as a virtual
+ * address.
+ */
 extern void *ioremap(unsigned long address, unsigned long size);
+
 #define ioremap_nocache(addr, size)	ioremap((addr), (size))
 extern int iounmap_explicit(void *addr, unsigned long size);
 extern void iounmap(void *addr);
 extern void * reserve_phb_iospace(unsigned long size);
 
-/*
- * Change virtual addresses to physical addresses and vv, for
- * addresses in the area where the kernel has the RAM mapped.
+/**
+ *	virt_to_phys	-	map virtual addresses to physical
+ *	@address: address to remap
+ *
+ *	The returned physical address is the physical (CPU) mapping for
+ *	the memory address given. It is only valid to use this function on
+ *	addresses directly mapped or allocated via kmalloc.
+ *
+ *	This function does not give bus mappings for DMA transfers. In
+ *	almost all conceivable cases a device driver should not be using
+ *	this function
  */
 static inline unsigned long virt_to_phys(volatile void * address)
 {
-#ifdef __IO_DEBUG
-	printk("virt_to_phys: 0x%08lx -> 0x%08lx\n", 
-			(unsigned long) address,
-			__pa((unsigned long)address));
-#endif
 	return __pa((unsigned long)address);
 }
 
+/**
+ *	phys_to_virt	-	map physical address to virtual
+ *	@address: address to remap
+ *
+ *	The returned virtual address is a current CPU mapping for
+ *	the memory address given. It is only valid to use this function on
+ *	addresses that have a kernel mapping
+ *
+ *	This function does not handle bus mappings for DMA transfers. In
+ *	almost all conceivable cases a device driver should not be using
+ *	this function
+ */
 static inline void * phys_to_virt(unsigned long address)
 {
-#ifdef __IO_DEBUG
-	printk("phys_to_virt: 0x%08lx -> 0x%08lx\n", address, __va(address));
-#endif
-	return (void *) __va(address);
+	return (void *)__va(address);
 }
 
 /*
@@ -204,6 +232,9 @@
 
 /*
  * 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)
 {
@@ -332,6 +363,17 @@
 #endif
 
 #ifdef __KERNEL__
+
+/**
+ *	check_signature		-	find BIOS signatures
+ *	@io_addr: mmio address to check
+ *	@signature:  signature block
+ *	@length: length of signature
+ *
+ *	Perform a signature comparison with the mmio address io_addr. This
+ *	address should have been obtained by ioremap.
+ *	Returns 1 on a match.
+ */
 static inline int check_signature(unsigned long io_addr,
 	const unsigned char *signature, int length)
 {
diff -Nru a/include/asm-ppc64/iommu.h b/include/asm-ppc64/iommu.h
--- a/include/asm-ppc64/iommu.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-ppc64/iommu.h	Sat Apr  3 19:38:54 2004
@@ -33,8 +33,6 @@
  */
 #define IOMAP_MAX_ORDER 10
 
-#define NO_TCE ((dma_addr_t)-1)
-
 /*
  * Tces come in two formats, one for the virtual bus and a different
  * format for PCI
@@ -151,5 +149,7 @@
 
 extern void pci_iommu_init(void);
 extern void pci_dma_init_direct(void);
+
+extern int ppc64_iommu_off;
 
 #endif
diff -Nru a/include/asm-ppc64/lmb.h b/include/asm-ppc64/lmb.h
--- a/include/asm-ppc64/lmb.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-ppc64/lmb.h	Sat Apr  3 19:38:55 2004
@@ -60,4 +60,6 @@
 extern unsigned long __init lmb_end_of_DRAM(void);
 extern unsigned long __init lmb_abs_to_phys(unsigned long);
 
+extern unsigned long io_hole_start;
+
 #endif /* _PPC64_LMB_H */
diff -Nru a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
--- a/include/asm-ppc64/machdep.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ppc64/machdep.h	Sat Apr  3 19:38:42 2004
@@ -65,8 +65,6 @@
 
 	void		(*setup_arch)(void);
 	/* Optional, may be NULL. */
-	void		(*setup_residual)(struct seq_file *m, int cpu_id);
-	/* Optional, may be NULL. */
 	void		(*get_cpuinfo)(struct seq_file *m);
 
 	void		(*init_IRQ)(void);
diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h
--- a/include/asm-ppc64/mmzone.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-ppc64/mmzone.h	Sat Apr  3 19:38:56 2004
@@ -28,7 +28,8 @@
 #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 -Nru a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
--- a/include/asm-ppc64/page.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-ppc64/page.h	Sat Apr  3 19:38:40 2004
@@ -38,10 +38,17 @@
 #define TASK_HPAGE_END_32	(0xc0000000UL)
 
 #define ARCH_HAS_HUGEPAGE_ONLY_RANGE
+#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
+
+#define is_hugepage_low_range(addr, len) \
+	(((addr) > (TASK_HPAGE_BASE_32-(len))) && ((addr) < TASK_HPAGE_END_32))
+#define is_hugepage_high_range(addr, len) \
+	(((addr) > (TASK_HPAGE_BASE-(len))) && ((addr) < TASK_HPAGE_END))
+
 #define is_hugepage_only_range(addr, len) \
-	( ((addr > (TASK_HPAGE_BASE-len)) && (addr < TASK_HPAGE_END)) || \
-	  (current->mm->context.low_hpages && \
-	   (addr > (TASK_HPAGE_BASE_32-len)) && (addr < TASK_HPAGE_END_32)) )
+	(is_hugepage_high_range((addr), (len)) || \
+	 (current->mm->context.low_hpages \
+	  && is_hugepage_low_range((addr), (len))))
 #define hugetlb_free_pgtables free_pgtables
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 
@@ -211,19 +218,6 @@
 #define __ba_to_bpn(x) ((((unsigned long)(x)) & ~REGION_MASK) >> PAGE_SHIFT)
 
 #define __va(x) ((void *)((unsigned long)(x) + KERNELBASE))
-
-/* Given that physical addresses do not map 1-1 to absolute addresses, we
- * use these macros to better specify exactly what we want to do.
- * The only restriction on their use is that the absolute address
- * macros cannot be used until after the LMB structure has been
- * initialized in prom.c.  -Peter
- */
-#define __v2p(x) ((void *) __pa(x))
-#define __v2a(x) ((void *) phys_to_absolute(__pa(x)))
-#define __p2a(x) ((void *) phys_to_absolute(x))
-#define __p2v(x) ((void *) __va(x))
-#define __a2p(x) ((void *) absolute_to_phys(x))
-#define __a2v(x) ((void *) __va(absolute_to_phys(x)))
 
 #ifdef CONFIG_DISCONTIGMEM
 #define page_to_pfn(page)	discontigmem_page_to_pfn(page)
diff -Nru a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
--- a/include/asm-ppc64/pci.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-ppc64/pci.h	Sat Apr  3 19:38:42 2004
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/dma-mapping.h>
 #include <asm/scatterlist.h>
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -112,17 +113,33 @@
 	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 */
@@ -151,6 +168,11 @@
 	if (pci_dma_ops.pci_dac_dma_supported)
 		return pci_dma_ops.pci_dac_dma_supported(hwdev, mask);
 	return 0;
+}
+
+static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
+{
+	return dma_mapping_error(dma_addr);
 }
 
 extern int pci_domain_nr(struct pci_bus *bus);
diff -Nru a/include/asm-ppc64/pmc.h b/include/asm-ppc64/pmc.h
--- a/include/asm-ppc64/pmc.h	Sat Apr  3 19:38:44 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/include/asm-ppc64/posix_types.h b/include/asm-ppc64/posix_types.h
--- a/include/asm-ppc64/posix_types.h	Sat Apr  3 19:38:57 2004
+++ b/include/asm-ppc64/posix_types.h	Sat Apr  3 19:38:57 2004
@@ -48,7 +48,7 @@
 
 #define	__FD_SET(d, set)	((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
 #define	__FD_CLR(d, set)	((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-#define	__FD_ISSET(d, set)	((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
+#define	__FD_ISSET(d, set)	(((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0)
 #define	__FD_ZERO(set)	\
   ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set)))
 
diff -Nru a/include/asm-ppc64/proc_fs.h b/include/asm-ppc64/proc_fs.h
--- a/include/asm-ppc64/proc_fs.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/include/asm-ppc64/proc_pmc.h b/include/asm-ppc64/proc_pmc.h
--- a/include/asm-ppc64/proc_pmc.h	Sat Apr  3 19:38:45 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
--- a/include/asm-ppc64/prom.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-ppc64/prom.h	Sat Apr  3 19:38:56 2004
@@ -87,11 +87,12 @@
 	} pci64;
 };
 
-struct _of_tce_table {
+struct of_tce_table {
 	phandle node;
 	unsigned long base;
 	unsigned long size;
 };
+extern struct of_tce_table of_tce_table[];
 
 struct reg_property {
 	unsigned long address;
diff -Nru a/include/asm-ppc64/rtas.h b/include/asm-ppc64/rtas.h
--- a/include/asm-ppc64/rtas.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-ppc64/rtas.h	Sat Apr  3 19:38:56 2004
@@ -177,6 +177,7 @@
 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 -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
--- a/include/asm-ppc64/unistd.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-ppc64/unistd.h	Sat Apr  3 19:38:40 2004
@@ -274,10 +274,6 @@
 
 #ifndef __ASSEMBLY__
 
-#include <linux/types.h>
-#include <linux/compiler.h>
-#include <linux/linkage.h>
-
 /* On powerpc a system call basically clobbers the same registers like a
  * function call, with the exception of LR (which is needed for the
  * "sc; bnslr" sequence) and CR (where only CR0.SO is clobbered to signal
@@ -399,20 +395,19 @@
 /*
  * 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)
+
 #endif /* __KERNEL_SYSCALLS__ */
 
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
-				unsigned long prot, unsigned long flags,
-				unsigned long fd, off_t offset);
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+
+unsigned long sys_mmap(unsigned long addr, size_t len, unsigned long prot,
+		       unsigned long flags, unsigned long fd, off_t offset);
 struct pt_regs;
 int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
 		unsigned long a3, unsigned long a4, unsigned long a5,
@@ -426,13 +421,11 @@
 int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3,
 		unsigned long p4, unsigned long p5, unsigned long p6,
 		struct pt_regs *regs);
-asmlinkage int sys_pipe(int *fildes);
+int sys_pipe(int *fildes);
 int sys_ptrace(long request, long pid, long addr, long data);
 struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
-				const struct sigaction __user *act,
-				struct sigaction __user *oact,
-				size_t sigsetsize);
+long sys_rt_sigaction(int sig, const struct sigaction __user *act,
+		      struct sigaction __user *oact, size_t sigsetsize);
 
 /*
  * "Conditional" syscalls
@@ -441,6 +434,8 @@
  * but it doesn't work on all toolchains, so we just do it by hand
  */
 #define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",.sys_ni_syscall");
+
+#endif		/* __KERNEL__ */
 
 #endif		/* __ASSEMBLY__ */
 
diff -Nru a/include/asm-ppc64/vio.h b/include/asm-ppc64/vio.h
--- a/include/asm-ppc64/vio.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-ppc64/vio.h	Sat Apr  3 19:38:45 2004
@@ -11,12 +11,14 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#ifndef _VIO_H
-#define _VIO_H
+#ifndef _ASM_VIO_H
+#define _ASM_VIO_H
 
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <asm/hvcall.h>
 #include <asm/prom.h>
 #include <asm/scatterlist.h>
@@ -44,8 +46,11 @@
 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 +70,33 @@
 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 {
@@ -106,4 +138,9 @@
 	return container_of(dev, struct vio_dev, dev);
 }
 
-#endif /* _PHYP_H */
+static inline int vio_dma_mapping_error(dma_addr_t dma_addr)
+{
+	return dma_mapping_error(dma_addr);
+}
+
+#endif /* _ASM_VIO_H */
diff -Nru a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
--- a/include/asm-s390/bitops.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-s390/bitops.h	Sat Apr  3 19:38:40 2004
@@ -532,7 +532,7 @@
  * Find-bit routines..
  */
 static inline int
-find_first_zero_bit(unsigned long * addr, unsigned int size)
+find_first_zero_bit(const unsigned long * addr, unsigned int size)
 {
 	unsigned long cmp, count;
         unsigned int res;
@@ -571,7 +571,7 @@
 }
 
 static inline int
-find_first_bit(unsigned long * addr, unsigned int size)
+find_first_bit(const unsigned long * addr, unsigned int size)
 {
 	unsigned long cmp, count;
         unsigned int res;
@@ -610,7 +610,7 @@
 }
 
 static inline int
-find_next_zero_bit (unsigned long * addr, int size, int offset)
+find_next_zero_bit (const unsigned long * addr, int size, int offset)
 {
         unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
         unsigned long bitvec, reg;
@@ -649,7 +649,7 @@
 }
 
 static inline int
-find_next_bit (unsigned long * addr, int size, int offset)
+find_next_bit (const unsigned long * addr, int size, int offset)
 {
         unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
         unsigned long bitvec, reg;
@@ -693,7 +693,7 @@
  * Find-bit routines..
  */
 static inline unsigned long
-find_first_zero_bit(unsigned long * addr, unsigned long size)
+find_first_zero_bit(const unsigned long * addr, unsigned long size)
 {
         unsigned long res, cmp, count;
 
@@ -735,7 +735,7 @@
 }
 
 static inline unsigned long
-find_first_bit(unsigned long * addr, unsigned long size)
+find_first_bit(const unsigned long * addr, unsigned long size)
 {
         unsigned long res, cmp, count;
 
@@ -777,7 +777,7 @@
 }
 
 static inline unsigned long
-find_next_zero_bit (unsigned long * addr, unsigned long size, unsigned long offset)
+find_next_zero_bit (const unsigned long * addr, unsigned long size, unsigned long offset)
 {
         unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
         unsigned long bitvec, reg;
@@ -821,7 +821,7 @@
 }
 
 static inline unsigned long
-find_next_bit (unsigned long * addr, unsigned long size, unsigned long offset)
+find_next_bit (const unsigned long * addr, unsigned long size, unsigned long offset)
 {
         unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
         unsigned long bitvec, reg;
diff -Nru a/include/asm-s390/cio.h b/include/asm-s390/cio.h
--- a/include/asm-s390/cio.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-s390/cio.h	Sat Apr  3 19:38:55 2004
@@ -132,6 +132,7 @@
 #define CCW_CMD_SENSE_PGID	0x34
 #define CCW_CMD_SUSPEND_RECONN	0x5B
 #define CCW_CMD_RDC		0x64
+#define CCW_CMD_RELEASE		0x94
 #define CCW_CMD_SET_PGID	0xAF
 #define CCW_CMD_SENSE_ID	0xE4
 #define CCW_CMD_DCTL		0xF3
diff -Nru a/include/asm-s390/compat.h b/include/asm-s390/compat.h
--- a/include/asm-s390/compat.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-s390/compat.h	Sat Apr  3 19:38:41 2004
@@ -15,6 +15,8 @@
 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 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 @@
 	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 -Nru a/include/asm-s390/elf.h b/include/asm-s390/elf.h
--- a/include/asm-s390/elf.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-s390/elf.h	Sat Apr  3 19:38:55 2004
@@ -155,9 +155,31 @@
 /* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
    now struct_user_regs, they are different) */
 
-#define ELF_CORE_COPY_REGS(pr_reg, regs)	\
-	memcpy(&pr_reg,regs,sizeof(elf_gregset_t)); \
+static inline int dump_regs(struct pt_regs *ptregs, elf_gregset_t *regs)
+{
+	memcpy(&regs->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs));
+	regs->orig_gpr2 = ptregs->orig_gpr2;
+	return 1;
+}
 
+#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs(regs, &pr_reg);
+
+static inline int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
+{
+	dump_regs(__KSTK_PTREGS(tsk), regs);
+	memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs));
+	return 1;
+}
+
+#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs(tsk, regs)
+
+static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
+{
+	memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t));
+	return 1;
+}
+
+#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs)
 
 
 /* This yields a mask that user programs can use to figure out what
diff -Nru a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
--- a/include/asm-s390/lowcore.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-s390/lowcore.h	Sat Apr  3 19:38:43 2004
@@ -44,6 +44,10 @@
 #define __LC_PGM_ILC                    0x08C
 #define __LC_PGM_INT_CODE               0x08E
 
+#define __LC_PER_ATMID			0x096
+#define __LC_PER_ADDRESS		0x098
+#define __LC_PER_ACCESS_ID		0x0A1
+
 #define __LC_SUBCHANNEL_ID              0x0B8
 #define __LC_SUBCHANNEL_NR              0x0BA
 #define __LC_IO_INT_PARM                0x0BC
@@ -60,7 +64,10 @@
 
 #ifndef __s390x__
 #define __LC_KERNEL_STACK               0xC40
-#define __LC_ASYNC_STACK                0xC44
+#define __LC_THREAD_INFO		0xC44
+#define __LC_ASYNC_STACK                0xC48
+#define __LC_KERNEL_ASCE		0xC4C
+#define __LC_USER_ASCE			0xC50
 #define __LC_CPUID                      0xC60
 #define __LC_CPUADDR                    0xC68
 #define __LC_IPLDEV                     0xC7C
@@ -69,13 +76,16 @@
 #define __LC_INT_CLOCK			0xC98
 #else /* __s390x__ */
 #define __LC_KERNEL_STACK               0xD40
-#define __LC_ASYNC_STACK                0xD48
+#define __LC_THREAD_INFO		0xD48
+#define __LC_ASYNC_STACK                0xD50
+#define __LC_KERNEL_ASCE		0xD58
+#define __LC_USER_ASCE			0xD60
 #define __LC_CPUID                      0xD90
 #define __LC_CPUADDR                    0xD98
 #define __LC_IPLDEV                     0xDB8
 #define __LC_JIFFY_TIMER		0xDC0
 #define __LC_CURRENT			0xDD8
-#define __LC_INT_CLOCK			0xDE8
+#define __LC_INT_CLOCK			0xDe8
 #endif /* __s390x__ */
 
 #define __LC_PANIC_MAGIC                0xE00
@@ -95,7 +105,6 @@
 #include <linux/config.h>
 #include <asm/processor.h>
 #include <linux/types.h>
-#include <asm/atomic.h>
 #include <asm/sigp.h>
 
 void restart_int_handler(void);
@@ -163,9 +172,12 @@
         /* System info area */
 	__u32        save_area[16];            /* 0xc00 */
 	__u32        kernel_stack;             /* 0xc40 */
-	__u32        async_stack;              /* 0xc44 */
+	__u32        thread_info;              /* 0xc44 */
+	__u32        async_stack;              /* 0xc48 */
+	__u32        kernel_asce;              /* 0xc4c */
+	__u32        user_asce;                /* 0xc50 */
+	__u8         pad10[0xc60-0xc54];       /* 0xc54 */
 	/* entry.S sensitive area start */
-	__u8         pad10[0xc60-0xc48];       /* 0xc5c */
 	struct       cpuinfo_S390 cpu_data;    /* 0xc60 */
 	__u32        ipl_device;               /* 0xc7c */
 	/* entry.S sensitive area end */
@@ -241,9 +253,12 @@
 	__u64        save_area[16];            /* 0xc00 */
         __u8         pad9[0xd40-0xc80];        /* 0xc80 */
  	__u64        kernel_stack;             /* 0xd40 */
-	__u64        async_stack;              /* 0xd48 */
+	__u64        thread_info;              /* 0xd48 */
+	__u64        async_stack;              /* 0xd50 */
+	__u64        kernel_asce;              /* 0xd58 */
+	__u64        user_asce;                /* 0xd60 */
+	__u8         pad10[0xd80-0xd68];       /* 0xd68 */
 	/* entry.S sensitive area start */
-	__u8         pad10[0xd80-0xd50];       /* 0xd64 */
 	struct       cpuinfo_S390 cpu_data;    /* 0xd80 */
 	__u32        ipl_device;               /* 0xdb8 */
 	__u32        pad11;                    /* 0xdbc */
diff -Nru a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
--- a/include/asm-s390/mmu_context.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-s390/mmu_context.h	Sat Apr  3 19:38:43 2004
@@ -24,22 +24,19 @@
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                              struct task_struct *tsk)
 {
-        unsigned long pgd;
-
         if (prev != next) {
 #ifndef __s390x__
-	        pgd = (__pa(next->pgd)&PAGE_MASK) | 
+	        S390_lowcore.user_asce = (__pa(next->pgd)&PAGE_MASK) |
                       (_SEGMENT_TABLE|USER_STD_MASK);
-                /* Load page tables */
-                asm volatile("    lctl  7,7,%0\n"   /* secondary space */
-                             "    lctl  13,13,%0\n" /* home space */
-                             : : "m" (pgd) );
+                /* Load home space page table origin. */
+                asm volatile("lctl  13,13,%0"
+			     : : "m" (S390_lowcore.user_asce) );
 #else /* __s390x__ */
-                pgd = (__pa(next->pgd)&PAGE_MASK) | (_REGION_TABLE|USER_STD_MASK);
-                /* Load page tables */
-                asm volatile("    lctlg 7,7,%0\n"   /* secondary space */
-                             "    lctlg 13,13,%0\n" /* home space */
-                             : : "m" (pgd) );
+                S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) |
+			(_REGION_TABLE|USER_STD_MASK);
+		/* Load home space page table origin. */
+		asm volatile("lctlg  13,13,%0"
+			     : : "m" (S390_lowcore.user_asce) );
 #endif /* __s390x__ */
         }
 	cpu_set(smp_processor_id(), next->cpu_vm_mask);
@@ -51,6 +48,7 @@
                                struct mm_struct *next)
 {
         switch_mm(prev, next, current);
+	set_fs(current->thread.mm_segment);
 }
 
 #endif
diff -Nru a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
--- a/include/asm-s390/pgtable.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-s390/pgtable.h	Sat Apr  3 19:38:55 2004
@@ -719,14 +719,14 @@
  * 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
- * for the offset.
- * 0|     offset      |0110|type |0
- * 00000000001111111111222222222233
- * 01234567890123456789012345678901
+ * 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 5 bits from 25-29 for the type and the 20 bits from 1-19
+ * plus 24 for the offset.
+ * 0|     offset        |0110|o|type |00|
+ * 0 0000000001111111111 2222 2 22222 33
+ * 0 1234567890123456789 0123 4 56789 01
  *
  * 64 bit swap entry format:
  * A page-table entry has some bits we have to treat in a special way.
@@ -736,29 +736,25 @@
  * 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
- * for the offset.
- * |                     offset                       |0110|type |0
- * 0000000000111111111122222222223333333333444444444455555555556666
- * 0123456789012345678901234567890123456789012345678901234567890123
+ * 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 5 bits from 57-61 for the type and the 53 bits from 0-51
+ * plus 56 for the offset.
+ * |                      offset                        |0110|o|type |00|
+ *  0000000000111111111122222222223333333333444444444455 5555 5 55566 66
+ *  0123456789012345678901234567890123456789012345678901 2345 6 78901 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;
-#ifndef __s390x__
-	BUG_ON((pte_val(pte) & 0x80000901) != 0);
-#else /* __s390x__ */
-	BUG_ON((pte_val(pte) & 0x901) != 0);
-#endif /* __s390x__ */
+	pte_val(pte) = _PAGE_INVALID_SWAP | ((type & 0x1f) << 2) |
+		((offset & 1) << 7) | ((offset & 0xffffe) << 11);
 	return pte;
 }
 
-#define __swp_type(entry)	(((entry).val >> 1) & 0x3f)
-#define __swp_offset(entry)	((entry).val >> 12)
+#define __swp_type(entry)	(((entry).val >> 2) & 0x1f)
+#define __swp_offset(entry)	(((entry).val >> 11) | (((entry).val >> 7) & 1))
 #define __swp_entry(type,offset) ((swp_entry_t) { pte_val(mk_swap_pte((type),(offset))) })
 
 #define __pte_to_swp_entry(pte)	((swp_entry_t) { pte_val(pte) })
diff -Nru a/include/asm-s390/processor.h b/include/asm-s390/processor.h
--- a/include/asm-s390/processor.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-s390/processor.h	Sat Apr  3 19:38:43 2004
@@ -82,10 +82,10 @@
  */
 struct thread_struct {
 	s390_fp_regs fp_regs;
-	unsigned int ar2;		/* kernel access register 2         */
-        unsigned int ar4;               /* kernel access register 4         */
+	unsigned int  acrs[NUM_ACRS];
         unsigned long ksp;              /* kernel stack pointer             */
         unsigned long user_seg;         /* HSTD                             */
+	mm_segment_t mm_segment;
         unsigned long prot_addr;        /* address of protection-excep.     */
         unsigned int error_code;        /* error-code of last prog-excep.   */
         unsigned int trap_no;
@@ -106,9 +106,10 @@
 
 #define INIT_THREAD {{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},	       \
 		     sizeof(init_stack) + (unsigned long) &init_stack,	       \
 		     __SWAPPER_PG_DIR,					       \
+		     {0},						       \
 		     0,0,0,						       \
 		     (per_struct) {{{{0,}}},0,0,0,0,{{0,}}},		       \
 		     0, 0						       \
@@ -167,7 +168,7 @@
 
 unsigned long get_wchan(struct task_struct *p);
 #define __KSTK_PTREGS(tsk) ((struct pt_regs *) \
-        (((unsigned long) tsk->thread_info + THREAD_SIZE - sizeof(struct pt_regs)) & -8L))
+        ((unsigned long) tsk->thread_info + THREAD_SIZE - sizeof(struct pt_regs)))
 #define KSTK_EIP(tsk)	(__KSTK_PTREGS(tsk)->psw.addr)
 #define KSTK_ESP(tsk)	(__KSTK_PTREGS(tsk)->gprs[15])
 
diff -Nru a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
--- a/include/asm-s390/ptrace.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-s390/ptrace.h	Sat Apr  3 19:38:54 2004
@@ -277,11 +277,16 @@
 			 PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
 			 PSW_MASK_PSTATE)
 
+/* This macro merges a NEW PSW mask specified by the user into
+   the currently active PSW mask CURRENT, modifying only those
+   bits in CURRENT that the user may be allowed to change: this
+   is the condition code and the program mask bits.  */
+#define PSW_MASK_MERGE(CURRENT,NEW) \
+	(((CURRENT) & ~(PSW_MASK_CC|PSW_MASK_PM)) | \
+	 ((NEW) & (PSW_MASK_CC|PSW_MASK_PM)))
+
 /*
- * The first entries in pt_regs and user_regs_struct
- * are common for the two structures. The s390_regs structure
- * covers the common parts. It simplifies copying the common part
- * between the three structures.
+ * The s390_regs structure is used to define the elf_gregset_t.
  */
 typedef struct
 {
@@ -291,6 +296,7 @@
 	unsigned long orig_gpr2;
 } s390_regs;
 
+#ifdef __KERNEL__
 /*
  * The pt_regs struct defines the way the registers are stored on
  * the stack during a system call.
@@ -299,11 +305,11 @@
 {
 	psw_t psw;
 	unsigned long gprs[NUM_GPRS];
-	unsigned int  acrs[NUM_ACRS];
 	unsigned long orig_gpr2;
 	unsigned short ilc;
 	unsigned short trap;
-} __attribute__ ((packed));
+};
+#endif
 
 /*
  * Now for the program event recording (trace) definitions.
diff -Nru a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
--- a/include/asm-s390/spinlock.h	Sat Apr  3 19:38:57 2004
+++ b/include/asm-s390/spinlock.h	Sat Apr  3 19:38:57 2004
@@ -35,13 +35,8 @@
  */
 
 typedef struct {
-#ifndef __s390x__
-	volatile unsigned long lock;
-} spinlock_t;
-#else /* __s390x__ */
 	volatile unsigned int lock;
 } __attribute__ ((aligned (4))) spinlock_t;
-#endif /* __s390x__ */
 
 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 #define spin_lock_init(lp) do { (lp)->lock = 0; } while(0)
@@ -80,11 +75,10 @@
 #else /* __s390x__ */
 	unsigned int result, reg;
 #endif /* __s390x__ */
-	__asm__ __volatile("    slr   %0,%0\n"
-			   "    basr  %1,0\n"
+	__asm__ __volatile("    basr  %1,0\n"
 			   "0:  cs    %0,%1,0(%3)"
-			   : "=&d" (result), "=&d" (reg), "=m" (lp->lock)
-			   : "a" (&lp->lock), "m" (lp->lock)
+			   : "=d" (result), "=&d" (reg), "=m" (lp->lock)
+			   : "a" (&lp->lock), "m" (lp->lock), "0" (0)
 			   : "cc", "memory" );
 	return !result;
 }
@@ -224,17 +218,15 @@
 	
 	__asm__ __volatile__(
 #ifndef __s390x__
-			     "   slr  %0,%0\n"
 			     "   lhi  %1,1\n"
 			     "   sll  %1,31\n"
 			     "   cs   %0,%1,0(%3)"
 #else /* __s390x__ */
-			     "   slgr  %0,%0\n"
 			     "   llihh %1,0x8000\n"
 			     "0: csg %0,%1,0(%3)\n"
 #endif /* __s390x__ */
-			     : "=&d" (result), "=&d" (reg), "=m" (rw->lock)
-			     : "a" (&rw->lock), "m" (rw->lock)
+			     : "=d" (result), "=&d" (reg), "=m" (rw->lock)
+			     : "a" (&rw->lock), "m" (rw->lock), "0" (0)
 			     : "cc", "memory" );
 	return result == 0;
 }
diff -Nru a/include/asm-s390/system.h b/include/asm-s390/system.h
--- a/include/asm-s390/system.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-s390/system.h	Sat Apr  3 19:38:56 2004
@@ -83,12 +83,31 @@
 		: : "a" (fpregs), "m" (*fpregs) );
 }
 
+static inline void save_access_regs(unsigned int *acrs)
+{
+	asm volatile ("stam 0,15,0(%0)" : : "a" (acrs) : "memory" );
+}
+
+static inline void restore_access_regs(unsigned int *acrs)
+{
+	asm volatile ("lam 0,15,0(%0)" : : "a" (acrs) );
+}
+
 #define switch_to(prev,next,last) do {					     \
 	if (prev == next)						     \
 		break;							     \
 	save_fp_regs(&prev->thread.fp_regs);				     \
 	restore_fp_regs(&next->thread.fp_regs);				     \
+	save_access_regs(&prev->thread.acrs[0]);			     \
+	restore_access_regs(&next->thread.acrs[0]);			     \
 	prev = __switch_to(prev,next);					     \
+} while (0)
+
+#define prepare_arch_switch(rq, next)	do { } while(0)
+#define task_running(rq, p)		((rq)->curr == (p))
+#define finish_arch_switch(rq, prev) do {				     \
+	set_fs(current->thread.mm_segment);				     \
+	spin_unlock_irq(&(rq)->lock);					     \
 } while (0)
 
 #define nop() __asm__ __volatile__ ("nop")
diff -Nru a/include/asm-s390/types.h b/include/asm-s390/types.h
--- a/include/asm-s390/types.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-s390/types.h	Sat Apr  3 19:38:43 2004
@@ -58,6 +58,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/config.h>
+
 typedef signed char s8;
 typedef unsigned char u8;
 
diff -Nru a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h
--- a/include/asm-s390/uaccess.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-s390/uaccess.h	Sat Apr  3 19:38:41 2004
@@ -36,10 +36,27 @@
 #define USER_DS         MAKE_MM_SEG(1)
 
 #define get_ds()        (KERNEL_DS)
-#define get_fs()        ({ mm_segment_t __x; \
-			   asm volatile("ear   %0,4":"=a" (__x)); \
-			   __x;})
-#define set_fs(x)       ({asm volatile("sar   4,%0"::"a" ((x).ar4));})
+#define get_fs()        (current->thread.mm_segment)
+
+#ifdef __s390x__
+#define set_fs(x) \
+({									\
+	unsigned long __pto;						\
+	current->thread.mm_segment = (x);				\
+	__pto = current->thread.mm_segment.ar4 ?			\
+		S390_lowcore.user_asce : S390_lowcore.kernel_asce;	\
+	asm volatile ("lctlg 7,7,%0" : : "m" (__pto) );			\
+})
+#else
+#define set_fs(x) \
+({									\
+	unsigned long __pto;						\
+	current->thread.mm_segment = (x);				\
+	__pto = current->thread.mm_segment.ar4 ?			\
+		S390_lowcore.user_asce : S390_lowcore.kernel_asce;	\
+	asm volatile ("lctl  7,7,%0" : : "m" (__pto) );			\
+})
+#endif
 
 #define segment_eq(a,b) ((a).ar4 == (b).ar4)
 
@@ -71,126 +88,64 @@
         unsigned long insn, fixup;
 };
 
-/*
- * Standard fixup section for uaccess inline functions.
- * local label 0: is the fault point
- * local label 1: is the return point
- * %0 is the error variable
- * %3 is the error value -EFAULT
- */
 #ifndef __s390x__
 #define __uaccess_fixup \
 	".section .fixup,\"ax\"\n"	\
-	"8: sacf  0\n"			\
-	"   lhi	  %0,%h3\n"		\
-	"   bras  4,9f\n"		\
-	"   .long 1b\n"			\
-	"9: l	  4,0(4)\n"		\
-	"   br	  4\n"			\
+	"2: lhi    %0,%4\n"		\
+	"   bras   1,3f\n"		\
+	"   .long  1b\n"		\
+	"3: l      1,0(1)\n"		\
+	"   br     1\n"			\
 	".previous\n"			\
 	".section __ex_table,\"a\"\n"	\
 	"   .align 4\n"			\
-	"   .long  0b,8b\n"		\
+	"   .long  0b,2b\n"		\
 	".previous"
+#define __uaccess_clobber "cc", "1"
 #else /* __s390x__ */
 #define __uaccess_fixup \
 	".section .fixup,\"ax\"\n"	\
-	"9: sacf  0\n"			\
-	"   lhi	  %0,%h3\n"		\
-	"   jg	  1b\n"			\
+	"2: lghi   %0,%4\n"		\
+	"   jg     1b\n"		\
 	".previous\n"			\
 	".section __ex_table,\"a\"\n"	\
 	"   .align 8\n"			\
-	"   .quad  0b,9b\n"		\
+	"   .quad  0b,2b\n"		\
 	".previous"
+#define __uaccess_clobber "cc"
 #endif /* __s390x__ */
 
 /*
  * These are the main single-value transfer routines.  They automatically
  * use the right size if we just have the right pointer type.
  */
-#ifndef __s390x__
-
-#define __put_user_asm_8(x, ptr, err) \
-({								\
-	register __typeof__(x) const * __from asm("2");		\
-	register __typeof__(*(ptr)) * __to asm("4");		\
-	__from = &(x);						\
-	__to = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: mvc	  0(8,%1),0(%2)\n"			\
-		"   sacf  0\n"					\
-		"1:\n"						\
-		__uaccess_fixup					\
-		: "=&d" (err)					\
-		: "a" (__to),"a" (__from),"K" (-EFAULT),"0" (0),\
-		  "m" (x) : "cc" );				\
-})
-
-#else /* __s390x__ */
-
-#define __put_user_asm_8(x, ptr, err) \
-({								\
-	register __typeof__(*(ptr)) * __ptr asm("4");		\
-	__ptr = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: stg	  %2,0(%1)\n"				\
-		"   sacf  0\n"					\
-		"1:\n"						\
-		__uaccess_fixup					\
-		: "=&d" (err)					\
-		: "a" (__ptr), "d" (x), "K" (-EFAULT), "0" (0)	\
-		: "cc" );					\
-})
-
-#endif /* __s390x__ */
-
-#define __put_user_asm_4(x, ptr, err) \
-({								\
-	register __typeof__(*(ptr)) * __ptr asm("4");		\
-	__ptr = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: st	  %2,0(%1)\n"				\
-		"   sacf  0\n"					\
-		"1:\n"						\
-		__uaccess_fixup					\
-		: "=&d" (err)					\
-		: "a" (__ptr), "d" (x), "K" (-EFAULT), "0" (0)	\
-		: "cc" );					\
-})
-
-#define __put_user_asm_2(x, ptr, err) \
+#if __GNUC__ > 2
+#define __put_user_asm(x, ptr, err) \
 ({								\
-	register __typeof__(*(ptr)) * __ptr asm("4");		\
-	__ptr = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: sth	  %2,0(%1)\n"				\
-		"   sacf  0\n"					\
+	err = 0;						\
+	asm volatile(						\
+		"0: mvcs  0(%1,%2),%3,%0\n"			\
 		"1:\n"						\
 		__uaccess_fixup					\
-		: "=&d" (err)					\
-		: "a" (__ptr), "d" (x), "K" (-EFAULT), "0" (0)	\
-		: "cc" );					\
+		: "+&d" (err)					\
+		: "d" (sizeof(*(ptr))), "a" (ptr), "Q" (x),	\
+		  "K" (-EFAULT)					\
+		: __uaccess_clobber );				\
 })
-
-#define __put_user_asm_1(x, ptr, err) \
+#else
+#define __put_user_asm(x, ptr, err) \
 ({								\
-	register __typeof__(*(ptr)) * __ptr asm("4");		\
-	__ptr = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: stc	  %2,0(%1)\n"				\
-		"   sacf  0\n"					\
+	err = 0;						\
+	asm volatile(						\
+		"0: mvcs  0(%1,%2),0(%3),%0\n"			\
 		"1:\n"						\
 		__uaccess_fixup					\
-		: "=&d" (err)					\
-		: "a" (__ptr), "d" (x),	"K" (-EFAULT), "0" (0)	\
-		: "cc" );					\
+		: "+&d" (err)					\
+		: "d" (sizeof(*(ptr))), "a" (ptr), "a" (&(x)),	\
+		  "K" (-EFAULT), "m" (x)			\
+		: __uaccess_clobber );				\
 })
+#endif
 
 #define __put_user(x, ptr) \
 ({								\
@@ -198,16 +153,10 @@
 	int __pu_err;						\
 	switch (sizeof (*(ptr))) {				\
 	case 1:							\
-		__put_user_asm_1(__x, ptr, __pu_err);		\
-		break;						\
 	case 2:							\
-		__put_user_asm_2(__x, ptr, __pu_err);		\
-		break;						\
 	case 4:							\
-		__put_user_asm_4(__x, ptr, __pu_err);		\
-		break;						\
 	case 8:							\
-		__put_user_asm_8(__x, ptr, __pu_err);		\
+		__put_user_asm(__x, ptr, __pu_err);		\
 		break;						\
 	default:						\
 		__pu_err = __put_user_bad();			\
@@ -225,90 +174,33 @@
 
 extern int __put_user_bad(void);
 
-#ifndef __s390x__
-
-#define __get_user_asm_8(x, ptr, err) \
+#if __GNUC__ > 2
+#define __get_user_asm(x, ptr, err) \
 ({								\
-	register __typeof__(*(ptr)) const * __from asm("4");	\
-	register __typeof__(x) * __to asm("2");			\
-	__from = (ptr);						\
-	__to = &(x);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: mvc	  0(8,%2),0(%4)\n"			\
-		"   sacf  0\n"					\
+	err = 0;						\
+	asm volatile (						\
+		"0: mvcp  %O1(%2,%R1),0(%3),%0\n"		\
 		"1:\n"						\
 		__uaccess_fixup					\
-		: "=&d" (err), "=m" (x)				\
-		: "a" (__to),"K" (-EFAULT),"a" (__from),"0" (0)	\
-		: "cc" );					\
+		: "+&d" (err), "=Q" (x)				\
+		: "d" (sizeof(*(ptr))), "a" (ptr),		\
+		  "K" (-EFAULT)					\
+		: __uaccess_clobber );				\
 })
-
-#else /* __s390x__ */
-
-#define __get_user_asm_8(x, ptr, err) \
-({								\
-	register __typeof__(*(ptr)) const * __ptr asm("4");	\
-	__ptr = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: lg	  %1,0(%2)\n"				\
-		"   sacf  0\n"					\
-		"1:\n"						\
-		__uaccess_fixup					\
-		: "=&d" (err), "=d" (x)				\
-		: "a" (__ptr), "K" (-EFAULT), "0" (0)		\
-		: "cc" );					\
-})
-
-#endif /* __s390x__ */
-
-
-#define __get_user_asm_4(x, ptr, err) \
-({								\
-	register __typeof__(*(ptr)) const * __ptr asm("4");	\
-	__ptr = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: l	  %1,0(%2)\n"				\
-		"   sacf  0\n"					\
-		"1:\n"						\
-		__uaccess_fixup					\
-		: "=&d" (err), "=d" (x)				\
-		: "a" (__ptr), "K" (-EFAULT), "0" (0)		\
-		: "cc" );					\
-})
-
-#define __get_user_asm_2(x, ptr, err) \
-({								\
-	register __typeof__(*(ptr)) const * __ptr asm("4");	\
-	__ptr = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sacf  512\n"				\
-		"0: lh	  %1,0(%2)\n"				\
-		"   sacf  0\n"					\
-		"1:\n"						\
-		__uaccess_fixup					\
-		: "=&d" (err), "=d" (x)				\
-		: "a" (__ptr), "K" (-EFAULT), "0" (0)		\
-		: "cc" );					\
-})
-
-#define __get_user_asm_1(x, ptr, err) \
+#else
+#define __get_user_asm(x, ptr, err) \
 ({								\
-	register __typeof__(*(ptr)) const * __ptr asm("4");	\
-	__ptr = (ptr);						\
-	__asm__ __volatile__ (					\
-		"   sr	  %1,%1\n"				\
-		"   sacf  512\n"				\
-		"0: ic	  %1,0(%2)\n"				\
-		"   sacf  0\n"					\
+	err = 0;						\
+	asm volatile (						\
+		"0: mvcp  0(%2,%5),0(%3),%0\n"			\
 		"1:\n"						\
 		__uaccess_fixup					\
-		: "=&d" (err), "=&d" (x)			\
-		: "a" (__ptr), "K" (-EFAULT), "0" (0)		\
-		: "cc" );					\
+		: "+&d" (err), "=m" (x)				\
+		: "d" (sizeof(*(ptr))), "a" (ptr),		\
+		  "K" (-EFAULT), "a" (&(x))			\
+		: __uaccess_clobber );				\
 })
+#endif
 
 #define __get_user(x, ptr)					\
 ({								\
@@ -316,16 +208,10 @@
 	int __gu_err;						\
 	switch (sizeof(*(ptr))) {				\
 	case 1:							\
-		__get_user_asm_1(__x, ptr, __gu_err);		\
-		break;						\
 	case 2:							\
-		__get_user_asm_2(__x, ptr, __gu_err);		\
-		break;						\
 	case 4:							\
-		__get_user_asm_4(__x, ptr, __gu_err);		\
-		break;						\
 	case 8:							\
-		__get_user_asm_8(__x, ptr, __gu_err);		\
+		__get_user_asm(__x, ptr, __gu_err);		\
 		break;						\
 	default:						\
 		__x = 0;					\
@@ -344,149 +230,123 @@
 
 extern int __get_user_bad(void);
 
-/*
- * access register are set up, that 4 points to secondary (user),
- * 2 to primary (kernel)
- */
-
-extern long __copy_to_user_asm(const void *from, long n, const void *to);
+extern long __copy_to_user_asm(const void *from, long n, void *to);
 
-#define __copy_to_user(to, from, n)                             \
-({                                                              \
-        __copy_to_user_asm(from, n, to);                        \
-})
+/**
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+static inline unsigned long
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+	return __copy_to_user_asm(from, n, to);
+}
 
-#define copy_to_user(to, from, n)                               \
-({                                                              \
-        long err = 0;                                           \
-        __typeof__(n) __n = (n);                                \
-        might_sleep();						\
-        if (__access_ok(to,__n)) {                              \
-                err = __copy_to_user_asm(from, __n, to);        \
-        }                                                       \
-        else                                                    \
-                err = __n;                                      \
-        err;                                                    \
-})
+/**
+ * copy_to_user: - Copy a block of data into user space.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+static inline unsigned long
+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);
+	return n;
+}
 
 extern long __copy_from_user_asm(void *to, long n, const void *from);
 
-#define __copy_from_user(to, from, n)                           \
-({                                                              \
-        __copy_from_user_asm(to, n, from);                      \
-})
-
-#define copy_from_user(to, from, n)                             \
-({                                                              \
-        long err = 0;                                           \
-        __typeof__(n) __n = (n);                                \
-        might_sleep();						\
-        if (__access_ok(from,__n)) {                            \
-                err = __copy_from_user_asm(to, __n, from);      \
-        }                                                       \
-        else                                                    \
-                err = __n;                                      \
-        err;                                                    \
-})
-
-extern long __copy_in_user_asm(const void *from, long n, void *to);
-
-#define __copy_in_user(to, from, n)				\
-({								\
-	__copy_in_user_asm(from, n, to);			\
-})
-
-#define copy_in_user(to, from, n)				\
-({								\
-	long err = 0;						\
-	__typeof__(n) __n = (n);				\
-	might_sleep();						\
-	if (__access_ok(from,__n) && __access_ok(to,__n)) {	\
-		err = __copy_in_user_asm(from, __n, to);	\
-	}							\
-	else							\
-		err = __n;					\
-	err;							\
-})
+/**
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+static inline unsigned long
+__copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+	return __copy_from_user_asm(to, n, from);
+}
 
-/*
- * Copy a null terminated string from userspace.
+/**
+ * copy_from_user: - Copy a block of data from user space.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
  */
+static inline unsigned long
+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);
+	else
+		memset(to, 0, n);
+	return n;
+}
 
-#ifndef __s390x__
+extern long __copy_in_user_asm(const void *from, long n, void *to);
 
-static inline long
-__strncpy_from_user(char *dst, const char *src, long count)
+static inline unsigned long
+__copy_in_user(void __user *to, const void __user *from, unsigned long n)
 {
-        int len;
-        __asm__ __volatile__ (
-		"   slr   %0,%0\n"
-		"   lr    2,%1\n"
-                "   lr    4,%2\n"
-                "   slr   3,3\n"
-                "   sacf  512\n"
-		"0: ic	  3,0(%0,4)\n"
-		"1: stc	  3,0(%0,2)\n"
-		"   ltr	  3,3\n"
-		"   jz	  2f\n"
-		"   ahi	  %0,1\n"
-		"   clr	  %0,%3\n"
-		"   jl	  0b\n"
-		"2: sacf  0\n"
-		".section .fixup,\"ax\"\n"
-		"3: lhi	  %0,%h4\n"
-		"   basr  3,0\n"
-		"   l	  3,4f-.(3)\n"
-		"   br	  3\n"
-		"4: .long 2b\n"
-		".previous\n"
-		".section __ex_table,\"a\"\n"
-		"   .align 4\n"
-		"   .long  0b,3b\n"
-		"   .long  1b,3b\n"
-		".previous"
-		: "=&a" (len)
-		: "a" (dst), "d" (src), "d" (count), "K" (-EFAULT)
-		: "2", "3", "4", "memory", "cc" );
-	return len;
+	__copy_in_user_asm(from, n, to);
 }
 
-#else /* __s390x__ */
-
-static inline long
-__strncpy_from_user(char *dst, const char *src, long count)
+static inline unsigned long
+copy_in_user(void __user *to, const void __user *from, unsigned long n)
 {
-	long len;
-	__asm__ __volatile__ (
-		"   slgr  %0,%0\n"
-		"   lgr	  2,%1\n"
-		"   lgr	  4,%2\n"
-		"   slr	  3,3\n"
-		"   sacf  512\n"
-		"0: ic	  3,0(%0,4)\n"
-		"1: stc	  3,0(%0,2)\n"
-		"   ltr	  3,3\n"
-		"   jz	  2f\n"
-		"   aghi  %0,1\n"
-		"   cgr	  %0,%3\n"
-		"   jl	  0b\n"
-		"2: sacf  0\n"
-		".section .fixup,\"ax\"\n"
-		"3: lghi  %0,%h4\n"
-		"   jg	  2b\n"	 
-		".previous\n"
-		".section __ex_table,\"a\"\n"
-		"   .align 8\n"
-		"   .quad  0b,3b\n"
-		"   .quad  1b,3b\n"
-		".previous"
-		: "=&a" (len)
-		: "a"  (dst), "d" (src), "d" (count), "K" (-EFAULT)
-		: "cc", "2" ,"3", "4" );
-	return len;
+	might_sleep();
+	if (__access_ok(from,n) && __access_ok(to,n))
+		n = __copy_in_user_asm(from, n, to);
+	return n;
 }
 
-#endif /* __s390x__ */
+/*
+ * Copy a null terminated string from userspace.
+ */
+extern long __strncpy_from_user_asm(char *dst, const char *src, long count);
 
 static inline long
 strncpy_from_user(char *dst, const char *src, long count)
@@ -494,104 +354,34 @@
         long res = -EFAULT;
         might_sleep();
         if (access_ok(VERIFY_READ, src, 1))
-                res = __strncpy_from_user(dst, src, count);
+                res = __strncpy_from_user_asm(dst, src, count);
         return res;
 }
 
 
-/*
- * Return the size of a string (including the ending 0)
- *
- * Return 0 for error
- */
-#ifndef __s390x__
+extern long __strnlen_user_asm(const char *src, long count);
 
 static inline unsigned long
 strnlen_user(const char * src, unsigned long n)
 {
 	might_sleep();
-	__asm__ __volatile__ (
-		"   alr   %0,%1\n"
-		"   slr   0,0\n"
-		"   lr    4,%1\n"
-		"   sacf  512\n"
-		"0: srst  %0,4\n"
-		"   jo    0b\n"
-		"   slr   %0,%1\n"
-		"   ahi   %0,1\n"
-		"   sacf  0\n"
-		"1:\n"
-		".section .fixup,\"ax\"\n"
-		"2: sacf  0\n"
-		"   slr   %0,%0\n"
-		"   bras  4,3f\n"
-		"   .long 1b\n"
-		"3: l     4,0(4)\n"
-		"   br    4\n"
-		".previous\n"
-		".section __ex_table,\"a\"\n"
-		"  .align 4\n"
-		"  .long  0b,2b\n"
-		".previous"
-		: "+&a" (n) : "d" (src)
-		: "cc", "0", "4" );
-	return n;
+	return __strnlen_user_asm(src, n);
 }
 
-#else /* __s390x__ */
-
-static inline unsigned long
-strnlen_user(const char * src, unsigned long n)
-{
-	might_sleep();
-#if 0
-	__asm__ __volatile__ (
-		"   algr  %0,%1\n"
-		"   slgr  0,0\n"
-		"   lgr	  4,%1\n"
-		"   sacf  512\n"
-		"0: srst  %0,4\n"
-		"   jo	0b\n"
-		"   slgr  %0,%1\n"
-		"   aghi  %0,1\n"
-		"1: sacf  0\n"
-		".section .fixup,\"ax\"\n"
-		"2: slgr  %0,%0\n"
-		"   jg	  1b\n"
-		".previous\n"
-		".section __ex_table,\"a\"\n"
-		"  .align 8\n"
-		"  .quad  0b,2b\n"
-		".previous"
-		: "+&a" (n) : "d" (src)
-		: "cc", "0", "4" );
-#else
-	__asm__ __volatile__ (
-		"   lgr	  4,%1\n"
-		"   sacf  512\n"
-		"0: cli   0(4),0x00\n"
-		"   la    4,1(4)\n"
-		"   je    1f\n"
-		"   brctg %0,0b\n"
-		"1: lgr	  %0,4\n"
-		"   slgr  %0,%1\n"
-		"2: sacf  0\n"
-		".section .fixup,\"ax\"\n"
-		"3: slgr  %0,%0\n"
-		"   jg    2b\n"  
-		".previous\n"
-		".section __ex_table,\"a\"\n"
-		"  .align 8\n"
-		"  .quad  0b,3b\n"
-		".previous"
-		: "+&a" (n) : "d" (src)
-		: "cc", "4" );
-#endif
-	return n;
-}
-
-#endif /* __s390x__ */
-
+/**
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ *
+ * 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)
 
 /*
@@ -600,17 +390,18 @@
 
 extern long __clear_user_asm(void *to, long n);
 
-#define __clear_user(to, n)					\
-({								\
-	__clear_user_asm(to, n);				\
-})
+static inline unsigned long
+__clear_user(void *to, unsigned long n)
+{
+	return __clear_user_asm(to, n);
+}
 
 static inline unsigned long
 clear_user(void *to, unsigned long n)
 {
 	might_sleep();
 	if (access_ok(VERIFY_WRITE, to, n))
-		n = __clear_user(to, n);
+		n = __clear_user_asm(to, n);
 	return n;
 }
 
diff -Nru a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h
--- a/include/asm-s390/unistd.h	Sat Apr  3 19:38:57 2004
+++ b/include/asm-s390/unistd.h	Sat Apr  3 19:38:57 2004
@@ -256,12 +256,15 @@
 #define __NR_clock_gettime	(__NR_timer_create+6)
 #define __NR_clock_getres	(__NR_timer_create+7)
 #define __NR_clock_nanosleep	(__NR_timer_create+8)
+
 /*
  * Number 263 is reserved for vserver
  */
 #define __NR_fadvise64_64	264
+#define __NR_statfs64		265
+#define __NR_fstatfs64		266
 
-#define NR_syscalls 265
+#define NR_syscalls 267
 
 /* 
  * There are some system calls that are not present on 64 bit, some
@@ -540,20 +543,14 @@
 	return sys_wait4(pid, wait_stat, flags, NULL);
 }
 struct mmap_arg_struct;
-asmlinkage long sys_mmap2(struct mmap_arg_struct *arg);
+asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg);
 
-asmlinkage int sys_execve(struct pt_regs regs);
-asmlinkage int sys_clone(struct pt_regs regs);
-asmlinkage int sys_fork(struct pt_regs regs);
-asmlinkage int sys_vfork(struct pt_regs regs);
-#ifndef CONFIG_ARCH_S390X
-#define __SYS_RETTYPE int
-#else
-#define __SYS_RETTYPE long
-#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);
+asmlinkage long sys_execve(struct pt_regs regs);
+asmlinkage long sys_clone(struct pt_regs regs);
+asmlinkage long sys_fork(struct pt_regs regs);
+asmlinkage long sys_vfork(struct pt_regs regs);
+asmlinkage long sys_pipe(unsigned long __user *fildes);
+asmlinkage long sys_ptrace(long request, long pid, long addr, long data);
 struct sigaction;
 asmlinkage long sys_rt_sigaction(int sig,
 				const struct sigaction __user *act,
diff -Nru a/include/asm-sh/cpu-sh3/cacheflush.h b/include/asm-sh/cpu-sh3/cacheflush.h
--- a/include/asm-sh/cpu-sh3/cacheflush.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-sh/cpu-sh3/cacheflush.h	Sat Apr  3 19:38:43 2004
@@ -37,5 +37,7 @@
 
 #define p3_cache_init()				do { } while (0)
 
+#define HAVE_ARCH_UNMAPPED_AREA
+
 #endif /* __ASM_CPU_SH3_CACHEFLUSH_H */
 
diff -Nru a/include/asm-sh/cpu-sh3/dac.h b/include/asm-sh/cpu-sh3/dac.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sh/cpu-sh3/dac.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,42 @@
+#ifndef __ASM_SH_DAC_H
+#define __ASM_SH_DAC_H
+
+/*
+ * Copyright (C) 2003  Andriy Skulysh
+ */
+
+
+#define DADR0	0xa40000a0
+#define DADR1	0xa40000a2
+#define DACR	0xa40000a4
+#define DACR_DAOE1	0x80
+#define DACR_DAOE0	0x40
+#define DACR_DAE	0x20
+
+
+static __inline__ void sh_dac_enable(int channel)
+{
+	unsigned char v;
+	v = ctrl_inb(DACR);
+	if(channel) v |= DACR_DAOE1;
+	else v |= DACR_DAOE0;
+	ctrl_outb(v,DACR);
+}
+
+static __inline__ void sh_dac_disable(int channel)
+{
+	unsigned char v;
+	v = ctrl_inb(DACR);
+	if(channel) v &= ~DACR_DAOE1;
+	else v &= ~DACR_DAOE0;
+	ctrl_outb(v,DACR);
+}
+
+static __inline__ void sh_dac_output(u8 value, int channel)
+{
+	if(channel) ctrl_outb(value,DADR1);
+	else ctrl_outb(value,DADR0);
+}
+
+#endif /* __ASM_SH_DAC_H */
+
diff -Nru a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h
--- a/include/asm-sh/cpu-sh4/dma.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-sh/cpu-sh4/dma.h	Sat Apr  3 19:38:45 2004
@@ -1,7 +1,7 @@
 #ifndef __ASM_CPU_SH4_DMA_H
 #define __ASM_CPU_SH4_DMA_H
 
-#define SH_DMAC_BASE	0xbfa00000
+#define SH_DMAC_BASE	0xffa00000
 
 #endif /* __ASM_CPU_SH4_DMA_H */
 
diff -Nru a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
--- a/include/asm-sh/dma-mapping.h	Sat Apr  3 19:38:57 2004
+++ b/include/asm-sh/dma-mapping.h	Sat Apr  3 19:38:57 2004
@@ -1 +1,165 @@
-#include <asm-generic/dma-mapping.h>
+#ifndef __ASM_SH_DMA_MAPPING_H
+#define __ASM_SH_DMA_MAPPING_H
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/device.h>
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+/* arch/sh/mm/consistent.c */
+extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
+extern void consistent_free(void *vaddr, size_t size);
+extern void consistent_sync(void *vaddr, size_t size, int direction);
+
+#ifdef CONFIG_SH_DREAMCAST
+struct pci_dev;
+extern struct bus_type pci_bus_type;
+extern void *__pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+				    dma_addr_t *dma_handle);
+extern void __pci_free_consistent(struct pci_dev *hwdev, size_t size,
+				  void *vaddr, dma_addr_t dma_handle);
+#endif
+
+#define dma_supported(dev, mask)	(1)
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, mask))
+		return -EIO;
+
+	*dev->dma_mask = mask;
+
+	return 0;
+}
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+			 dma_addr_t *dma_handle, int flag)
+{
+	/*
+	 * Some platforms have special pci_alloc_consistent() implementations,
+	 * in these instances we can't use the generic consistent_alloc().
+	 */
+#ifdef CONFIG_SH_DREAMCAST
+	if (dev && dev->bus == &pci_bus_type)
+		return __pci_alloc_consistent(NULL, size, dma_handle);
+#endif
+
+	return consistent_alloc(flag, size, dma_handle);
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+		       void *vaddr, dma_addr_t dma_handle)
+{
+	/*
+	 * Same note as above applies to pci_free_consistent()..
+	 */
+#ifdef CONFIG_SH_DREAMCAST
+	if (dev && dev->bus == &pci_bus_type) {
+		__pci_free_consistent(NULL, size, vaddr, dma_handle);
+		return;
+	}
+#endif
+
+	consistent_free(vaddr, size);
+}
+
+static inline void dma_cache_sync(void *vaddr, size_t size,
+				  enum dma_data_direction dir)
+{
+	consistent_sync(vaddr, size, (int)dir);
+}
+
+static inline dma_addr_t dma_map_single(struct device *dev,
+					void *ptr, size_t size,
+					enum dma_data_direction dir)
+{
+#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+	if (dev->bus == &pci_bus_type)
+		return virt_to_bus(ptr);
+#endif
+	dma_cache_sync(ptr, size, dir);
+
+	return virt_to_bus(ptr);
+}
+
+#define dma_unmap_single(dev, addr, size, dir)	do { } while (0)
+
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+			     int nents, enum dma_data_direction dir)
+{
+	int i;
+
+	for (i = 0; i < nents; i++) {
+#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+		dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+			       sg[i].length, dir);
+#endif
+		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+	}
+
+	return nents;
+}
+
+#define dma_unmap_sg(dev, sg, nents, dir)	do { } while (0)
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+				      unsigned long offset, size_t size,
+				      enum dma_data_direction dir)
+{
+	return dma_map_single(dev, page_address(page) + offset, size, dir);
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+				  size_t size, enum dma_data_direction dir)
+{
+	dma_unmap_single(dev, dma_address, size, dir);
+}
+
+static inline void dma_sync_single(struct device *dev, dma_addr_t dma_handle,
+				   size_t size, enum dma_data_direction dir)
+{
+#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+	if (dev->bus == &pci_bus_type)
+		return;
+#endif
+	dma_cache_sync(bus_to_virt(dma_handle), size, dir);
+}
+
+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 dir)
+{
+#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+	if (dev->bus == &pci_bus_type)
+		return;
+#endif
+	dma_cache_sync(bus_to_virt(dma_handle) + offset, size, dir);
+}
+
+static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
+			       int nelems, enum dma_data_direction dir)
+{
+	int i;
+
+	for (i = 0; i < nelems; i++) {
+#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
+		dma_cache_sync(page_address(sg[i].page) + sg[i].offset,
+			       sg[i].length, dir);
+#endif
+		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+	}
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+	/*
+	 * Each processor family will define its own L1_CACHE_SHIFT,
+	 * L1_CACHE_BYTES wraps to this, so this is always safe.
+	 */
+	return L1_CACHE_BYTES;
+}
+
+#endif /* __ASM_SH_DMA_MAPPING_H */
+
diff -Nru a/include/asm-sh/dma.h b/include/asm-sh/dma.h
--- a/include/asm-sh/dma.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-sh/dma.h	Sat Apr  3 19:38:41 2004
@@ -12,6 +12,7 @@
 
 #include <linux/config.h>
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 #include <asm/cpu/dma.h>
 #include <asm/semaphore.h>
 
@@ -63,11 +64,13 @@
 	unsigned long dar;
 
 	unsigned int configured:1;
+	unsigned int tei_capable:1;
 	atomic_t busy;
 
 	struct semaphore sem;
+	wait_queue_head_t wait_queue;
 	struct dma_ops *ops;
-} __attribute__ ((packed));
+};
 
 /* arch/sh/drivers/dma/dma-api.c */
 extern int dma_xfer(unsigned int chan, unsigned long from,
diff -Nru a/include/asm-sh/dreamcast/io.h b/include/asm-sh/dreamcast/io.h
--- a/include/asm-sh/dreamcast/io.h	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,49 +0,0 @@
-/*
- *	$Id: io.h,v 1.3 2003/05/04 19:30:14 lethal Exp $
- *	IO functions for SEGA Dreamcast
- */
-
-#ifndef _ASM_SH_IO_DREAMCAST_H
-#define _ASM_SH_IO_DREAMCAST_H
-
-#include <asm/io_generic.h>
-
-unsigned long dreamcast_isa_port2addr(unsigned long offset);
-
-#ifdef __WANT_IO_DEF
-
-# define __inb			generic_inb
-# define __inw			generic_inw
-# define __inl			generic_inl
-# define __outb			generic_outb
-# define __outw			generic_outw
-# define __outl			generic_outl
-
-# define __inb_p		generic_inb_p
-# define __inw_p		generic_inw
-# define __inl_p		generic_inl
-# define __outb_p		generic_outb_p
-# define __outw_p		generic_outw
-# define __outl_p		generic_outl
-
-# define __insb			generic_insb
-# define __insw			generic_insw
-# define __insl			generic_insl
-# define __outsb		generic_outsb
-# define __outsw		generic_outsw
-# define __outsl		generic_outsl
-
-# define __readb		generic_readb
-# define __readw		generic_readw
-# define __readl		generic_readl
-# define __writeb		generic_writeb
-# define __writew		generic_writew
-# define __writel		generic_writel
-
-# define __isa_port2addr	dreamcast_isa_port2addr
-# define __ioremap		generic_ioremap
-# define __iounmap		generic_iounmap
-
-#endif
-
-#endif /* _ASM_SH_IO_DREAMCAST_H */
diff -Nru a/include/asm-sh/hd64461/hd64461.h b/include/asm-sh/hd64461/hd64461.h
--- a/include/asm-sh/hd64461/hd64461.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-sh/hd64461/hd64461.h	Sat Apr  3 19:38:43 2004
@@ -1,12 +1,24 @@
 #ifndef __ASM_SH_HD64461
 #define __ASM_SH_HD64461
 /*
- *	$Id: hd64461.h,v 1.4 2004/02/01 19:46:04 lethal Exp $
+ *	$Id: hd64461.h,v 1.5 2004/03/16 00:07:51 lethal Exp $
  *	Copyright (C) 2000 YAEGASHI Takeshi
  *	Hitachi HD64461 companion chip support
  */
 #include <linux/config.h>
 
+/* Constants for PCMCIA mappings */
+#define HD64461_PCC_WINDOW	0x01000000
+
+#define HD64461_PCC0_BASE	0xb8000000	/* area 6 */
+#define HD64461_PCC0_ATTR	(HD64461_PCC0_BASE)
+#define HD64461_PCC0_COMM	(HD64461_PCC0_BASE+HD64461_PCC_WINDOW)
+#define HD64461_PCC0_IO		(HD64461_PCC0_BASE+2*HD64461_PCC_WINDOW)
+
+#define HD64461_PCC1_BASE	0xb4000000	/* area 5 */
+#define HD64461_PCC1_ATTR	(HD64461_PCC1_BASE)
+#define HD64461_PCC1_COMM	(HD64461_PCC1_BASE+HD64461_PCC_WINDOW)
+
 #define HD64461_STBCR	0x10000
 #define HD64461_STBCR_CKIO_STBY			0x2000
 #define HD64461_STBCR_SAFECKE_IST		0x1000
@@ -21,7 +33,7 @@
 #define HD64461_STBCR_STM0ST			0x0008
 #define HD64461_STBCR_STM1ST			0x0004
 #define HD64461_STBCR_SIRST				0x0002
-#define HD64461_STBCR_SURTSD			0x0001
+#define HD64461_STBCR_SURTST			0x0001
 
 #define HD64461_SYSCR	0x10002
 #define HD64461_SCPUCR	0x10004
@@ -77,16 +89,74 @@
 #define HD64461_BBTROPR		0x11068
 #define HD64461_BBTMDR		0x1106a
 
-#define HD64461_PCC0ISR         0x12000
-#define HD64461_PCC0GCR         0x12002
-#define HD64461_PCC0CSCR        0x12004
-#define HD64461_PCC0CSCIER      0x12006
-#define HD64461_PCC0SCR         0x12008
-#define HD64461_PCC1ISR         0x12010
-#define HD64461_PCC1GCR         0x12012
-#define HD64461_PCC1CSCR        0x12014
-#define HD64461_PCC1CSCIER      0x12016
-#define HD64461_PCC1SCR         0x12018
+/* PC Card Controller Registers */
+#define HD64461_PCC0ISR         0x12000 /* socket 0 interface status */
+#define HD64461_PCC0GCR         0x12002 /* socket 0 general control */
+#define HD64461_PCC0CSCR        0x12004 /* socket 0 card status change */
+#define HD64461_PCC0CSCIER      0x12006 /* socket 0 card status change interrupt enable */
+#define HD64461_PCC0SCR         0x12008 /* socket 0 software control */
+#define HD64461_PCC1ISR         0x12010 /* socket 1 interface status */
+#define HD64461_PCC1GCR         0x12012 /* socket 1 general control */
+#define HD64461_PCC1CSCR        0x12014 /* socket 1 card status change */
+#define HD64461_PCC1CSCIER      0x12016 /* socket 1 card status change interrupt enable */
+#define HD64461_PCC1SCR         0x12018 /* socket 1 software control */
+
+/* PCC Interface Status Register */
+#define HD64461_PCCISR_READY		0x80	/* card ready */
+#define HD64461_PCCISR_MWP		0x40	/* card write-protected */
+#define HD64461_PCCISR_VS2		0x20	/* voltage select pin 2 */
+#define HD64461_PCCISR_VS1		0x10	/* voltage select pin 1 */
+#define HD64461_PCCISR_CD2		0x08	/* card detect 2 */
+#define HD64461_PCCISR_CD1		0x04	/* card detect 1 */
+#define HD64461_PCCISR_BVD2		0x02	/* battery 1 */
+#define HD64461_PCCISR_BVD1		0x01	/* battery 1 */
+
+#define HD64461_PCCISR_PCD_MASK		0x0c    /* card detect */
+#define HD64461_PCCISR_BVD_MASK	0x03    /* battery voltage */
+#define HD64461_PCCISR_BVD_BATGOOD	0x03    /* battery good */
+#define HD64461_PCCISR_BVD_BATWARN	0x01    /* battery low warning */
+#define HD64461_PCCISR_BVD_BATDEAD1	0x02    /* battery dead */
+#define HD64461_PCCISR_BVD_BATDEAD2	0x00    /* battery dead */
+
+/* PCC General Control Register */
+#define HD64461_PCCGCR_DRVE		0x80    /* output drive */
+#define HD64461_PCCGCR_PCCR		0x40    /* PC card reset */
+#define HD64461_PCCGCR_PCCT		0x20    /* PC card type, 1=IO&mem, 0=mem */
+#define HD64461_PCCGCR_VCC0		0x10    /* voltage control pin VCC0SEL0 */
+#define HD64461_PCCGCR_PMMOD		0x08    /* memory mode */
+#define HD64461_PCCGCR_PA25		0x04    /* pin A25 */
+#define HD64461_PCCGCR_PA24		0x02    /* pin A24 */
+#define HD64461_PCCGCR_REG		0x01    /* pin PCC0REG# */
+
+/* PCC Card Status Change Register */
+#define HD64461_PCCCSCR_SCDI		0x80    /* sw card detect intr */
+#define HD64461_PCCCSCR_SRV1		0x40    /* reserved */
+#define HD64461_PCCCSCR_IREQ		0x20    /* IREQ intr req */
+#define HD64461_PCCCSCR_SC		0x10    /* STSCHG (status change) pin */
+#define HD64461_PCCCSCR_CDC		0x08    /* CD (card detect) change */
+#define HD64461_PCCCSCR_RC		0x04    /* READY change */
+#define HD64461_PCCCSCR_BW		0x02    /* battery warning change */
+#define HD64461_PCCCSCR_BD		0x01    /* battery dead change */
+
+/* PCC Card Status Change Interrupt Enable Register */
+#define HD64461_PCCCSCIER_CRE		0x80    /* change reset enable */
+#define HD64461_PCCCSCIER_IREQE_MASK   	0x60   /* IREQ enable */
+#define HD64461_PCCCSCIER_IREQE_DISABLED	0x00   /* IREQ disabled */
+#define HD64461_PCCCSCIER_IREQE_LEVEL  	0x20   /* IREQ level-triggered */
+#define HD64461_PCCCSCIER_IREQE_FALLING	0x40   /* IREQ falling-edge-trig */
+#define HD64461_PCCCSCIER_IREQE_RISING 	0x60   /* IREQ rising-edge-trig */
+
+#define HD64461_PCCCSCIER_SCE		0x10    /* status change enable */
+#define HD64461_PCCCSCIER_CDE		0x08    /* card detect change enable */
+#define HD64461_PCCCSCIER_RE		0x04    /* ready change enable */
+#define HD64461_PCCCSCIER_BWE		0x02    /* battery warn change enable */
+#define HD64461_PCCCSCIER_BDE		0x01    /* battery dead change enable*/
+
+/* PCC Software Control Register */
+#define HD64461_PCCSCR_VCC1		0x02	/* voltage control pin 1 */
+#define HD64461_PCCSCR_SWP		0x01    /* write protect */
+
+
 #define HD64461_P0OCR           0x1202a
 #define HD64461_P1OCR           0x1202c
 #define HD64461_PGCR            0x1202e
@@ -120,5 +190,14 @@
 
 #define HD64461_IRQBASE		OFFCHIP_IRQ_BASE
 #define HD64461_IRQ_NUM 	16
+
+#define HD64461_IRQ_UART    	(HD64461_IRQBASE+5)
+#define HD64461_IRQ_IRDA    	(HD64461_IRQBASE+6)
+#define HD64461_IRQ_TMU1   	(HD64461_IRQBASE+9)
+#define HD64461_IRQ_TMU0  	(HD64461_IRQBASE+10)
+#define HD64461_IRQ_GPIO    	(HD64461_IRQBASE+11)
+#define HD64461_IRQ_AFE     	(HD64461_IRQBASE+12)
+#define HD64461_IRQ_PCC1 	(HD64461_IRQBASE+13)
+#define HD64461_IRQ_PCC0 	(HD64461_IRQBASE+14)
 
 #endif
diff -Nru a/include/asm-sh/hd64461/io.h b/include/asm-sh/hd64461/io.h
--- a/include/asm-sh/hd64461/io.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-sh/hd64461/io.h	Sat Apr  3 19:38:45 2004
@@ -23,15 +23,21 @@
 extern unsigned char hd64461_inb_p(unsigned long port);
 extern void hd64461_outb_p(unsigned char value, unsigned long port);
 
-extern void hd64461_insb(unsigned long port, const void *buffer, unsigned long count);
-extern void hd64461_insw(unsigned long port, const void *buffer, unsigned long count);
-extern void hd64461_insl(unsigned long port, const void *buffer, unsigned long count);
+extern void hd64461_insb(unsigned long port, void *addr, unsigned long count);
+extern void hd64461_insw(unsigned long port, void *addr, unsigned long count);
+extern void hd64461_insl(unsigned long port, void *addr, unsigned long count);
 
 extern void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count);
 extern void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count);
 extern void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count);
 
+extern unsigned short hd64461_readw(unsigned long addr);
+extern void hd64461_writew(unsigned short b, unsigned long addr);
+
 
 extern int hd64461_irq_demux(int irq);
+extern void hd64461_register_irq_demux(int irq,
+		int (*demux)(int irq, void *dev), void *dev);
+extern void hd64461_unregister_irq_demux(int irq);
 
 #endif /* _ASM_SH_IO_HD64461_H */
diff -Nru a/include/asm-sh/hp6xx/hp6xx.h b/include/asm-sh/hp6xx/hp6xx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sh/hp6xx/hp6xx.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,19 @@
+#ifndef __ASM_SH_HP6XX_H
+#define __ASM_SH_HP6XX_H
+
+/*
+ * Copyright (C) 2003  Andriy Skulysh
+ */
+
+
+#define DAC_LCD_BRIGHTNESS		0
+#define DAC_SPEAKER_VOLUME		1
+
+#define HD64461_GPADR_SPEAKER	0x01
+#define HD64461_GPADR_PCMCIA0	(0x02|0x08)
+#define HD64461_GPBDR_LCDOFF	0x01
+#define HD64461_GPBDR_LED_RED	0x80
+
+
+#endif /* __ASM_SH_HP6XX_H */
+
diff -Nru a/include/asm-sh/irq.h b/include/asm-sh/irq.h
--- a/include/asm-sh/irq.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-sh/irq.h	Sat Apr  3 19:38:41 2004
@@ -30,6 +30,11 @@
 #define TIMER_IPR_POS	 3
 #define TIMER_PRIORITY	 2
 
+#define TIMER1_IRQ	17
+#define TIMER1_IPR_ADDR	INTC_IPRA
+#define TIMER1_IPR_POS	 2
+#define TIMER1_PRIORITY	 4
+
 #define RTC_IRQ		22
 #define RTC_IPR_ADDR	INTC_IPRA
 #define RTC_IPR_POS	 0
@@ -154,7 +159,7 @@
 # define OFFCHIP_NR_IRQS 16
 #else
 # if defined(CONFIG_HD64461)
-#  define OFFCHIP_NR_IRQS 16
+#  define OFFCHIP_NR_IRQS 18
 # elif defined (CONFIG_SH_BIGSUR) /* must be before CONFIG_HD64465 */
 #  define OFFCHIP_NR_IRQS 48
 # elif defined(CONFIG_HD64465)
diff -Nru a/include/asm-sh/page.h b/include/asm-sh/page.h
--- a/include/asm-sh/page.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-sh/page.h	Sat Apr  3 19:38:55 2004
@@ -21,6 +21,18 @@
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 #define PTE_MASK	PAGE_MASK
 
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+#define HPAGE_SHIFT	16
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
+#define HPAGE_SHIFT	20
+#endif
+
+#ifdef CONFIG_HUGETLB_PAGE
+#define HPAGE_SIZE		(1UL << HPAGE_SHIFT)
+#define HPAGE_MASK		(~(HPAGE_SIZE-1))
+#define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT-PAGE_SHIFT)
+#endif
+
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 
diff -Nru a/include/asm-sh/pci.h b/include/asm-sh/pci.h
--- a/include/asm-sh/pci.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-sh/pci.h	Sat Apr  3 19:38:45 2004
@@ -3,9 +3,7 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
-#include <linux/mm.h>		/* for struct page */
-#include <asm/cacheflush.h>
+#include <linux/dma-mapping.h>
 
 /* Can be used to override the logic in pci_scan_bus for skipping
    already-configured bus numbers - to be used for buggy BIOSes
@@ -59,45 +57,6 @@
 #include <linux/string.h>
 #include <asm/io.h>
 
-/* Allocate and map kernel buffer using consistent mode DMA for a device.
- * hwdev should be valid struct pci_dev pointer for PCI devices,
- * NULL for PCI-like buses (ISA, EISA).
- * Returns non-NULL cpu-view pointer to the buffer if successful and
- * sets *dma_addrp to the pci side dma address as well, else *dma_addrp
- * is undefined.
- */
-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-				  dma_addr_t *dma_handle);
-
-/* Free and unmap a consistent DMA buffer.
- * cpu_addr is what was returned from pci_alloc_consistent,
- * size must be the same as what as passed into pci_alloc_consistent,
- * and likewise dma_addr must be the same as what *dma_addrp was set to.
- *
- * References to the memory and mappings associated with cpu_addr/dma_addr
- * past this call are illegal.
- */
-extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-				void *vaddr, dma_addr_t dma_handle);
-
-/* Map a single buffer of the indicated size for DMA in streaming mode.
- * 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.
- */
-static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-					size_t size, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-                BUG();
-
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-	dma_cache_wback_inv(ptr, size);
-#endif
-	return virt_to_bus(ptr);
-}
-
 /* pci_unmap_{single,page} being a nop depends upon the
  * configuration.
  */
@@ -123,117 +82,6 @@
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do { } while (0)
 #endif
 
-/* Unmap a single streaming mode DMA translation.  The dma_addr and size
- * must match what was provided for in a previous pci_map_single call.  All
- * other usages are undefined.
- *
- * After this call, reads by the cpu to the buffer are guaranteed to see
- * whatever the device wrote there.
- */
-static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-				    size_t size,int direction)
-{
-	/* Nothing to do */
-}
-
-/* Map a set of buffers described by scatterlist in streaming
- * mode for DMA.  This is the scather-gather version of the
- * above pci_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).
- *
- * NOTE: An implementation may be able to use a smaller number of
- *       DMA address/length pairs than there are SG table elements.
- *       (for example via virtual mapping capabilities)
- *       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
- * the same here.
- */
-static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-			     int nents, int direction)
-{
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-	int i;
-
-	for (i=0; i<nents; i++) {
-		dma_cache_wback_inv(page_address(sg[i].page) + sg[i].offset, sg[i].length);
-		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
-	}
-#endif
-	if (direction == PCI_DMA_NONE)
-                BUG();
-
-	return nents;
-}
-
-/* Unmap a set of streaming mode DMA translations.
- * Again, cpu read rules concerning calls here are the same as for
- * pci_unmap_single() above.
- */
-static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-				int nents, int direction)
-{
-	/* Nothing to do */
-}
-
-/* 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
- * 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)
-{
-	if (direction == PCI_DMA_NONE)
-                BUG();
-
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-	dma_cache_wback_inv(bus_to_virt(dma_handle), size);
-#endif
-	
-}
-
-/* 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.
- */
-static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
-				   struct scatterlist *sg,
-				   int nelems, int direction)
-{
-	if (direction == PCI_DMA_NONE)
-                BUG();
-
-#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
-	int i;
-
-	for (i=0; i<nelems; i++) {
-		dma_cache_wback_inv(page_address(sg[i].page) + sg[i].offset, sg[i].length);
-		sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
-	}
-#endif
-}
-
-
-/* Return whether the given PCI device DMA address mask can
- * be supported properly.  For example, if your device can
- * only drive the low 24-bits during PCI bus mastering, then
- * you would pass 0x00ffffff as the mask to this function.
- */
-static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
-{
-	return 1;
-}
-
 /* Not supporting more than 32-bit PCI bus addresses now, but
  * must satisfy references to this function.  Change if needed.
  */
@@ -264,6 +112,9 @@
 
 /* generic pci stuff */
 #include <asm-generic/pci.h>
+
+/* generic DMA-mapping stuff */
+#include <asm-generic/pci-dma-compat.h>
 
 #endif /* __ASM_SH_PCI_H */
 
diff -Nru a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
--- a/include/asm-sh/pgtable.h	Sat Apr  3 19:38:57 2004
+++ b/include/asm-sh/pgtable.h	Sat Apr  3 19:38:57 2004
@@ -53,20 +53,20 @@
 #define VMALLOC_START	(P3SEG+0x00100000)
 #define VMALLOC_END	P4SEG
 
-/*			0x001     WT-bit on SH-4, 0 on SH-3 */
+#define	_PAGE_WT	0x001  /* WT-bit on SH-4, 0 on SH-3 */
 #define _PAGE_HW_SHARED	0x002  /* SH-bit  : page is shared among processes */
 #define _PAGE_DIRTY	0x004  /* D-bit   : page changed */
 #define _PAGE_CACHABLE	0x008  /* C-bit   : cachable */
-/*			0x010     SZ0-bit : Size of page */
+#define _PAGE_SZ0	0x010  /* SZ0-bit : Size of page */
 #define _PAGE_RW	0x020  /* PR0-bit : write access allowed */
 #define _PAGE_USER	0x040  /* PR1-bit : user space access allowed */
-/*			0x080     SZ1-bit : Size of page (on SH-4) */
+#define _PAGE_SZ1	0x080  /* SZ1-bit : Size of page (on SH-4) */
 #define _PAGE_PRESENT	0x100  /* V-bit   : page is valid */
 #define _PAGE_PROTNONE	0x200  /* software: if not present  */
 #define _PAGE_ACCESSED 	0x400  /* software: page referenced */
 #define _PAGE_U0_SHARED 0x800  /* software: page is shared in user space */
 
-#define	_PAGE_FILE	0x080  /* software: pagecache or swap? */
+#define	_PAGE_FILE	_PAGE_WT  /* software: pagecache or swap? */
 
 /* software: moves to PTEA.TC (Timing Control) */
 #define _PAGE_PCC_AREA5	0x00000000	/* use BSC registers for area5 */
@@ -83,20 +83,29 @@
 
 
 /* Mask which drop software flags
- * We also drop SZ1 bit since it is always 0 and used for _PAGE_FILE
+ * We also drop WT bit since it is used for _PAGE_FILE
  * bit in this implementation.
  */
+#define _PAGE_CLEAR_FLAGS	(_PAGE_WT | _PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_U0_SHARED)
+
 #if defined(CONFIG_CPU_SH3)
 /*
  * MMU on SH-3 has bug on SH-bit: We can't use it if MMUCR.IX=1.
  * Work around: Just drop SH-bit.
  */
-#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff17c
+#define _PAGE_FLAGS_HARDWARE_MASK	(0x1fffffff & ~(_PAGE_CLEAR_FLAGS | _PAGE_HW_SHARED))
 #else
-#define _PAGE_FLAGS_HARDWARE_MASK	0x1ffff17e
+#define _PAGE_FLAGS_HARDWARE_MASK	(0x1fffffff & ~(_PAGE_CLEAR_FLAGS))
+#endif
+
+/* Hardware flags: SZ0=1 (4k-byte) */
+#define _PAGE_FLAGS_HARD	_PAGE_SZ0
+
+#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K)
+#define _PAGE_SZHUGE	(_PAGE_SZ1)
+#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB)
+#define _PAGE_SZHUGE	(_PAGE_SZ0 | _PAGE_SZ1)
 #endif
-/* Hardware flags: SZ=1 (4k-byte) */
-#define _PAGE_FLAGS_HARD		0x00000010
 
 #define _PAGE_SHARED	_PAGE_U0_SHARED
 
@@ -194,6 +203,8 @@
 	prot &= ~_PAGE_CACHABLE;
 	return __pgprot(prot);
 }
+
+#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
diff -Nru a/include/asm-sh/processor.h b/include/asm-sh/processor.h
--- a/include/asm-sh/processor.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-sh/processor.h	Sat Apr  3 19:38:42 2004
@@ -22,6 +22,7 @@
 
 /* Core Processor Version Register */
 #define CCN_PVR		0xff000030
+#define CCN_CVR		0xff000040
 #define CCN_PRR		0xff000044
 
 /*
diff -Nru a/include/asm-sh/sh2000/io.h b/include/asm-sh/sh2000/io.h
--- a/include/asm-sh/sh2000/io.h	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,56 +0,0 @@
-/*
- * include/asm-sh/io_sh2000.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- *           2001 SUGIOKA Toshinobu (sugioka@itonet.co.jp)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License.  See linux/COPYING for more information.
- *
- * IO functions for use when we don't know what machine we are on
- */
-
-#ifndef _ASM_SH_IO_SH2000_H
-#define _ASM_SH_IO_SH2000_H
-
-#include <asm/io_generic.h>
-
-unsigned long sh2000_isa_port2addr(unsigned long offset);
-
-#ifdef __WANT_IO_DEF
-
-# define __inb			generic_inb
-# define __inw			generic_inw
-# define __inl			generic_inl
-# define __outb			generic_outb
-# define __outw			generic_outw
-# define __outl			generic_outl
-
-# define __inb_p		generic_inb_p
-# define __inw_p		generic_inw
-# define __inl_p		generic_inl
-# define __outb_p		generic_outb_p
-# define __outw_p		generic_outw
-# define __outl_p		generic_outl
-
-# define __insb			generic_insb
-# define __insw			generic_insw
-# define __insl			generic_insl
-# define __outsb		generic_outsb
-# define __outsw		generic_outsw
-# define __outsl		generic_outsl
-
-# define __readb		generic_readb
-# define __readw		generic_readw
-# define __readl		generic_readl
-# define __writeb		generic_writeb
-# define __writew		generic_writew
-# define __writel		generic_writel
-
-# define __isa_port2addr	sh2000_isa_port2addr
-# define __ioremap		generic_ioremap
-# define __iounmap		generic_iounmap
-
-#endif
-
-#endif /* _ASM_SH_IO_SH2000_H */
diff -Nru a/include/asm-sh/signal.h b/include/asm-sh/signal.h
--- a/include/asm-sh/signal.h	Sat Apr  3 19:38:44 2004
+++ b/include/asm-sh/signal.h	Sat Apr  3 19:38:44 2004
@@ -7,6 +7,10 @@
 struct pt_regs;
 struct siginfo;
 
+#ifdef __KERNEL__
+/* Most things should be clean enough to redefine this at will, if care
+   is taken to make libc match.  */
+
 #define _NSIG		64
 #define _NSIG_BPW	32
 #define _NSIG_WORDS	(_NSIG / _NSIG_BPW)
@@ -16,6 +20,14 @@
 typedef struct {
 	unsigned long sig[_NSIG_WORDS];
 } sigset_t;
+
+#else
+/* Here we must cater to libcs that poke about in kernel headers.  */
+
+#define NSIG		32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
 
 #define SIGHUP		 1
 #define SIGINT		 2
diff -Nru a/include/asm-sh/types.h b/include/asm-sh/types.h
--- a/include/asm-sh/types.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-sh/types.h	Sat Apr  3 19:38:55 2004
@@ -35,6 +35,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/config.h>
+
 typedef __signed__ char s8;
 typedef unsigned char u8;
 
diff -Nru a/include/asm-sparc/asmmacro.h b/include/asm-sparc/asmmacro.h
--- a/include/asm-sparc/asmmacro.h	Sat Apr  3 19:38:44 2004
+++ b/include/asm-sparc/asmmacro.h	Sat Apr  3 19:38:44 2004
@@ -18,27 +18,6 @@
 #define GET_PROCESSOR4D_ID(reg) \
 	lda	[%g0] ASI_M_VIKING_TMP1, %reg;
 
-/* Blackbox */
-#define GET_PROCESSOR_ID(reg) \
-	sethi	%hi(___b_smp_processor_id), %reg; \
-	sethi	%hi(boot_cpu_id), %reg; \
-	ldub	[%reg + %lo(boot_cpu_id)], %reg;
-
-#define GET_PROCESSOR_MID(reg, tmp) \
-	rd	%tbr, %reg; \
-	sethi	%hi(mid_xlate), %tmp; \
-	srl	%reg, 12, %reg; \
-	or	%tmp, %lo(mid_xlate), %tmp; \
-	and	%reg, 3, %reg; \
-	ldub	[%tmp + %reg], %reg;
-
-#define GET_PROCESSOR_OFFSET(reg, tmp) \
-	GET_PROCESSOR_ID(reg) \
-	sethi	%hi(cpu_offset), %tmp; \
-	sll	%reg, 2, %reg; \
-	or	%tmp, %lo(cpu_offset), %tmp; \
-	ld	[%tmp + %reg], %reg;
-
 /* All trap entry points _must_ begin with this macro or else you
  * lose.  It makes sure the kernel has a proper window so that
  * c-code can be called.
diff -Nru a/include/asm-sparc/bugs.h b/include/asm-sparc/bugs.h
--- a/include/asm-sparc/bugs.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-sparc/bugs.h	Sat Apr  3 19:38:41 2004
@@ -1,7 +1,17 @@
-/*  $Id: bugs.h,v 1.5 1995/11/25 02:31:18 davem Exp $
+/*  $Id: bugs.h,v 1.1 1996/12/26 13:25:20 davem Exp $
  *  include/asm-sparc/bugs.h:  Sparc probes for various bugs.
  *
- *  Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
-static void check_bugs(void) { }
+#include <asm/cpudata.h>
+#include <linux/config.h>
+
+extern unsigned long loops_per_jiffy;
+
+static void check_bugs(void)
+{
+#ifndef CONFIG_SMP
+	cpu_data(0).udelay_val = loops_per_jiffy;
+#endif
+}
diff -Nru a/include/asm-sparc/cpudata.h b/include/asm-sparc/cpudata.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-sparc/cpudata.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,26 @@
+/* cpudata.h: Per-cpu parameters.
+ *
+ * Copyright (C) 2004 Keith M Wesolowski (wesolows@foobazco.org)
+ *
+ * Based on include/asm-sparc64/cpudata.h and Linux 2.4 smp.h
+ * both (C) David S. Miller.
+ */
+
+#ifndef _SPARC_CPUDATA_H
+#define _SPARC_CPUDATA_H
+
+#include <linux/percpu.h>
+
+typedef struct {
+	unsigned long udelay_val;
+	unsigned long clock_tick;
+	unsigned int multiplier;
+	unsigned int counter;
+	int prom_node;
+	int mid;
+} cpuinfo_sparc;
+
+DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
+#define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu))
+
+#endif /* _SPARC_CPUDATA_H */
diff -Nru a/include/asm-sparc/delay.h b/include/asm-sparc/delay.h
--- a/include/asm-sparc/delay.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-sparc/delay.h	Sat Apr  3 19:38:42 2004
@@ -7,7 +7,8 @@
 #ifndef __SPARC_DELAY_H
 #define __SPARC_DELAY_H
 
-extern unsigned long loops_per_jiffy;
+#include <linux/config.h>
+#include <asm/cpudata.h>
 
 extern __inline__ void __delay(unsigned long loops)
 {
@@ -20,7 +21,15 @@
 }
 
 /* This is too messy with inline asm on the Sparc. */
-extern void udelay(unsigned long usecs);
-extern void ndelay(unsigned long usecs);
+extern void __udelay(unsigned long usecs, unsigned long lpj);
+extern void __ndelay(unsigned long nsecs, unsigned long lpj);
+
+#ifdef CONFIG_SMP
+#define __udelay_val	cpu_data(smp_processor_id()).udelay_val
+#else /* SMP */
+#define __udelay_val	loops_per_jiffy
+#endif /* SMP */
+#define udelay(__usecs)	__udelay(__usecs, __udelay_val)
+#define ndelay(__nsecs)	__ndelay(__nsecs, __udelay_val)
 
 #endif /* defined(__SPARC_DELAY_H) */
diff -Nru a/include/asm-sparc/ide.h b/include/asm-sparc/ide.h
--- a/include/asm-sparc/ide.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-sparc/ide.h	Sat Apr  3 19:38:43 2004
@@ -53,24 +53,8 @@
 	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
-/*
- * This registers the standard ports for this architecture with the IDE
- * driver.
- */
-static __inline__ void ide_init_default_hwifs(void)
-{
-#ifndef CONFIG_PCI
-	hw_regs_t hw;
-	int index;
-
-	for (index = 0; index < MAX_HWIFS; index++) {
-		memset(&hw, 0, sizeof hw);
-		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
-		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
-	}
-#endif
-}
+/* There are no standard ports. */
+static inline void ide_init_default_hwifs(void)	{ ; }
 
 #define __ide_insl(data_reg, buffer, wcount) \
 	__ide_insw(data_reg, buffer, (wcount)<<1)
diff -Nru a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h
--- a/include/asm-sparc/oplib.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-sparc/oplib.h	Sat Apr  3 19:38:56 2004
@@ -306,6 +306,11 @@
 extern void prom_apply_generic_ranges(int node, int parent, 
 				      struct linux_prom_registers *sbusregs, int nregs);
 
+/* CPU probing helpers.  */
+int cpu_find_by_instance(int instance, int *prom_node, int *mid);
+int cpu_find_by_mid(int mid, int *prom_node);
+int cpu_get_hwmid(int prom_node);
+
 extern spinlock_t prom_lock;
 
 #endif /* !(__SPARC_OPLIB_H) */
diff -Nru a/include/asm-sparc/page.h b/include/asm-sparc/page.h
--- a/include/asm-sparc/page.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-sparc/page.h	Sat Apr  3 19:38:42 2004
@@ -156,17 +156,22 @@
 #define PAGE_ALIGN(addr)  (((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 #define PAGE_OFFSET	0xf0000000
-#define __pa(x)                 ((unsigned long)(x) - PAGE_OFFSET)
-#define __va(x)                 ((void *)((unsigned long) (x) + PAGE_OFFSET))
+#ifndef __ASSEMBLY__
+extern unsigned long phys_base;
+extern unsigned long pfn_base;
+#endif
+#define __pa(x)			((unsigned long)(x) - PAGE_OFFSET + phys_base)
+#define __va(x)			((void *)((unsigned long) (x) - phys_base + PAGE_OFFSET))
 
-#define virt_to_phys(x)		__pa((unsigned long)(x))
-#define phys_to_virt(x)		__va((unsigned long)(x))
+#define virt_to_phys		__pa
+#define phys_to_virt		__va
 
-#define pfn_to_page(pfn)        (mem_map + (pfn))
-#define page_to_pfn(page)       ((unsigned long)((page) - mem_map))
-#define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
-#define pfn_valid(pfn)		((pfn) < max_mapnr)
-#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_page(pfn)	(mem_map + ((pfn)-(pfn_base)))
+#define page_to_pfn(page)	((unsigned long)(((page) - mem_map) + pfn_base))
+#define virt_to_page(kaddr)	(mem_map + ((((unsigned long)(kaddr)-PAGE_OFFSET)>>PAGE_SHIFT)))
+
+#define pfn_valid(pfn)		(((pfn) >= (pfn_base)) && (((pfn)-(pfn_base)) < max_mapnr))
+#define virt_addr_valid(kaddr)	((((unsigned long)(kaddr)-PAGE_OFFSET)>>PAGE_SHIFT) < max_mapnr)
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
diff -Nru a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h
--- a/include/asm-sparc/pci.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-sparc/pci.h	Sat Apr  3 19:38:54 2004
@@ -52,7 +52,7 @@
  * 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 @@
  * 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 -Nru a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
--- a/include/asm-sparc/pgtable.h	Sat Apr  3 19:38:44 2004
+++ b/include/asm-sparc/pgtable.h	Sat Apr  3 19:38:44 2004
@@ -181,6 +181,7 @@
  * hit for all __pa()/__va() operations.
  */
 extern unsigned long phys_base;
+extern unsigned long pfn_base;
 
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
diff -Nru a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h
--- a/include/asm-sparc/sbus.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-sparc/sbus.h	Sat Apr  3 19:38:41 2004
@@ -118,8 +118,12 @@
 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 -Nru a/include/asm-sparc/semaphore.h b/include/asm-sparc/semaphore.h
--- a/include/asm-sparc/semaphore.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-sparc/semaphore.h	Sat Apr  3 19:38:56 2004
@@ -26,7 +26,7 @@
 #endif
 
 #define __SEMAPHORE_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+{ ATOMIC24_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
 	__SEM_DEBUG_INIT(name) }
 
 #define __MUTEX_INITIALIZER(name) \
diff -Nru a/include/asm-sparc/shmparam.h b/include/asm-sparc/shmparam.h
--- a/include/asm-sparc/shmparam.h	Sat Apr  3 19:38:57 2004
+++ b/include/asm-sparc/shmparam.h	Sat Apr  3 19:38:57 2004
@@ -2,6 +2,8 @@
 #ifndef _ASMSPARC_SHMPARAM_H
 #define _ASMSPARC_SHMPARAM_H
 
+#define __ARCH_FORCE_SHMLBA 	1
+
 extern int vac_cache_size;
 #define SHMLBA (vac_cache_size ? vac_cache_size : \
 		(sparc_cpu_model == sun4c ? (64 * 1024) : \
diff -Nru a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h
--- a/include/asm-sparc/smp.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-sparc/smp.h	Sat Apr  3 19:38:42 2004
@@ -15,17 +15,7 @@
 
 #include <linux/cpumask.h>
 
-/* PROM provided per-processor information we need
- * to start them all up.
- */
-
-struct prom_cpuinfo {
-	int prom_node;
-	int mid;
-};
-extern int linux_num_cpus;	/* number of CPUs probed  */
-
-#endif /* !(__ASSEMBLY__) */
+#endif /* __ASSEMBLY__ */
 
 #ifdef CONFIG_SMP
 
@@ -33,27 +23,15 @@
 
 #include <asm/ptrace.h>
 #include <asm/asi.h>
-
-extern struct prom_cpuinfo linux_cpus[NR_CPUS];
-
-/* Per processor Sparc parameters we need. */
-
-struct cpuinfo_sparc {
-	unsigned long udelay_val; /* that's it */
-	unsigned short next;
-	unsigned short mid;
-};
-
-extern struct cpuinfo_sparc cpu_data[NR_CPUS];
-extern unsigned long cpu_offset[NR_CPUS];
+#include <asm/atomic.h>
 
 /*
  *	Private routines/data
  */
  
 extern unsigned char boot_cpu_id;
-extern unsigned long cpu_present_map;
-#define cpu_online_map cpu_present_map
+extern cpumask_t phys_cpu_present_map;
+#define cpu_possible_map phys_cpu_present_map
 
 typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
 		       unsigned long, unsigned long);
@@ -70,13 +48,13 @@
 void smp_store_cpu_info(int);
 
 struct seq_file;
-void smp_bogo_info(struct seq_file *);
+void smp_bogo(struct seq_file *);
 void smp_info(struct seq_file *);
 
 BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, smp_message_pass, int, int, unsigned long, int)
-BTFIXUPDEF_CALL(int, __smp_processor_id, void)
-BTFIXUPDEF_BLACKBOX(smp_processor_id)
+BTFIXUPDEF_CALL(int, __hard_smp_processor_id, void)
+BTFIXUPDEF_BLACKBOX(hard_smp_processor_id)
 BTFIXUPDEF_BLACKBOX(load_current)
 
 #define smp_cross_call(func,arg1,arg2,arg3,arg4,arg5) BTFIXUP_CALL(smp_cross_call)(func,arg1,arg2,arg3,arg4,arg5)
@@ -105,7 +83,6 @@
 
 extern __volatile__ int __cpu_number_map[NR_CPUS];
 extern __volatile__ int __cpu_logical_map[NR_CPUS];
-extern unsigned long smp_proc_in_lock[NR_CPUS];
 
 extern __inline__ int cpu_logical_map(int cpu)
 {
@@ -152,7 +129,7 @@
 	   			     "=&r" (cpuid));
 	   See btfixup.h and btfixupprep.c to understand how a blackbox works.
 	 */
-	__asm__ __volatile__("sethi %%hi(___b_smp_processor_id), %0\n\t"
+	__asm__ __volatile__("sethi %%hi(___b_hard_smp_processor_id), %0\n\t"
 			     "sethi %%hi(boot_cpu_id), %0\n\t"
 			     "ldub [%0 + %%lo(boot_cpu_id)], %0\n\t" :
 			     "=&r" (cpuid));
@@ -164,14 +141,17 @@
 	int cpuid;
 	
 	__asm__ __volatile__("mov %%o7, %%g1\n\t"
-			     "call ___f___smp_processor_id\n\t"
+			     "call ___f___hard_smp_processor_id\n\t"
 			     " nop\n\t"
 			     "mov %%g2, %0\n\t" : "=r"(cpuid) : : "g1", "g2");
 	return cpuid;
 }
 #endif
 
-#define smp_processor_id() hard_smp_processor_id()
+#define smp_processor_id()	(current_thread_info()->cpu)
+
+#define prof_multiplier(__cpu)		cpu_data(__cpu).multiplier
+#define prof_counter(__cpu)		cpu_data(__cpu).counter
 
 #endif /* !(__ASSEMBLY__) */
 
@@ -189,7 +169,7 @@
 #define MBOX_IDLECPU2         0xFD
 #define MBOX_STOPCPU2         0xFE
 
-#endif /* !(CONFIG_SMP) */
+#endif /* SMP */
 
 #define NO_PROC_ID            0xFF
 
diff -Nru a/include/asm-sparc/thread_info.h b/include/asm-sparc/thread_info.h
--- a/include/asm-sparc/thread_info.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-sparc/thread_info.h	Sat Apr  3 19:38:56 2004
@@ -100,9 +100,6 @@
  * 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 -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-sparc/unistd.h	Sat Apr  3 19:38:41 2004
@@ -453,6 +453,8 @@
 static __inline__ _syscall1(int,_exit,int,exitcode)
 static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
+#include <linux/linkage.h>
+
 asmlinkage unsigned long sys_mmap(
 				unsigned long addr, unsigned long len,
 				unsigned long prot, unsigned long flags,
diff -Nru a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h
--- a/include/asm-sparc64/ide.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-sparc64/ide.h	Sat Apr  3 19:38:42 2004
@@ -54,24 +54,8 @@
 	hw->io_ports[IDE_IRQ_OFFSET] = 0;
 }
 
-/*
- * This registers the standard ports for this architecture with the IDE
- * driver.
- */
-static __inline__ void ide_init_default_hwifs(void)
-{
-#ifndef CONFIG_BLK_DEV_IDEPCI
-	hw_regs_t hw;
-	int index;
-
-	for (index = 0; index < MAX_HWIFS; index++) {
-		memset(&hw, 0, sizeof hw);
-		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
-		hw.irq = ide_default_irq(ide_default_io_base(index));
-		ide_register_hw(&hw, NULL);
-	}
-#endif /* CONFIG_BLK_DEV_IDEPCI */
-}
+/* There are no standard ports. */
+static inline void ide_init_default_hwifs(void)	{ ; }
 
 #define __ide_insl(data_reg, buffer, wcount) \
 	__ide_insw(data_reg, buffer, (wcount)<<1)
diff -Nru a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
--- a/include/asm-sparc64/page.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-sparc64/page.h	Sat Apr  3 19:38:43 2004
@@ -48,8 +48,8 @@
 
 #define pte_val(x)	((x).pte)
 #define iopte_val(x)	((x).iopte)
-#define pmd_val(x)      ((unsigned long)(x).pmd)
-#define pgd_val(x)	((unsigned long)(x).pgd)
+#define pmd_val(x)      ((x).pmd)
+#define pgd_val(x)	((x).pgd)
 #define ctxd_val(x)	((x).ctxd)
 #define pgprot_val(x)	((x).pgprot)
 #define iopgprot_val(x)	((x).iopgprot)
@@ -74,8 +74,8 @@
 
 #define pte_val(x)	(x)
 #define iopte_val(x)	(x)
-#define pmd_val(x)      ((unsigned long)(x))
-#define pgd_val(x)	((unsigned long)(x))
+#define pmd_val(x)      (x)
+#define pgd_val(x)	(x)
 #define ctxd_val(x)	(x)
 #define pgprot_val(x)	(x)
 #define iopgprot_val(x)	(x)
diff -Nru a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
--- a/include/asm-sparc64/pci.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-sparc64/pci.h	Sat Apr  3 19:38:41 2004
@@ -60,7 +60,7 @@
  * 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 @@
  * 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 @@
 #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,18 +191,33 @@
 	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.
 	 */
+}
+
+#define PCI_DMA_ERROR_CODE	(~(dma_addr_t)0x0)
+
+static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
+{
+	return (dma_addr == PCI_DMA_ERROR_CODE);
 }
 
 /* Return the index of the PCI controller for device PDEV. */
diff -Nru a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
--- a/include/asm-sparc64/pgalloc.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-sparc64/pgalloc.h	Sat Apr  3 19:38:56 2004
@@ -38,11 +38,12 @@
 
 	preempt_disable();
 	if (!page->lru.prev) {
-		(unsigned long *)page->lru.next = pgd_quicklist;
+		page->lru.next = (void *) pgd_quicklist;
 		pgd_quicklist = (unsigned long *)page;
 	}
-	(unsigned long)page->lru.prev |=
-		(((unsigned long)pgd & (PAGE_SIZE / 2)) ? 2 : 1);
+	page->lru.prev = (void *)
+	  (((unsigned long)page->lru.prev) |
+	   (((unsigned long)pgd & (PAGE_SIZE / 2)) ? 2 : 1));
 	pgd_cache_size++;
 	preempt_enable();
 }
@@ -62,7 +63,7 @@
 			off = PAGE_SIZE / 2;
 			mask &= ~2;
 		}
-		(unsigned long)ret->lru.prev = mask;
+		ret->lru.prev = (void *) mask;
 		if (!mask)
 			pgd_quicklist = (unsigned long *)ret->lru.next;
                 ret = (struct page *)(__page_address(ret) + off);
@@ -76,10 +77,10 @@
 		if (page) {
 			ret = (struct page *)page_address(page);
 			clear_page(ret);
-			(unsigned long)page->lru.prev = 2;
+			page->lru.prev = (void *) 2UL;
 
 			preempt_disable();
-			(unsigned long *)page->lru.next = pgd_quicklist;
+			page->lru.next = (void *) pgd_quicklist;
 			pgd_quicklist = (unsigned long *)page;
 			pgd_cache_size++;
 			preempt_enable();
diff -Nru a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h
--- a/include/asm-sparc64/sbus.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-sparc64/sbus.h	Sat Apr  3 19:38:41 2004
@@ -111,7 +111,11 @@
 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 -Nru a/include/asm-sparc64/shmparam.h b/include/asm-sparc64/shmparam.h
--- a/include/asm-sparc64/shmparam.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-sparc64/shmparam.h	Sat Apr  3 19:38:43 2004
@@ -4,6 +4,7 @@
 
 #include <asm/spitfire.h>
 
+#define __ARCH_FORCE_SHMLBA	1
 /* attach addr a multiple of this */
 #define	SHMLBA	((PAGE_SIZE > L1DCACHE_SIZE) ? PAGE_SIZE : L1DCACHE_SIZE)
 
diff -Nru a/include/asm-sparc64/siginfo.h b/include/asm-sparc64/siginfo.h
--- a/include/asm-sparc64/siginfo.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-sparc64/siginfo.h	Sat Apr  3 19:38:54 2004
@@ -8,6 +8,7 @@
 
 #define __ARCH_SI_PREAMBLE_SIZE	(4 * sizeof(int))
 #define __ARCH_SI_TRAPNO
+#define __ARCH_SI_BAND_T int
 
 #include <asm-generic/siginfo.h>
 
diff -Nru a/include/asm-sparc64/svr4.h b/include/asm-sparc64/svr4.h
--- a/include/asm-sparc64/svr4.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-sparc64/svr4.h	Sat Apr  3 19:38:45 2004
@@ -87,7 +87,7 @@
 
 /* signal stack execution place, unsupported */
 typedef struct svr4_stack_t {
-        char *sp;
+        u32  sp;
         int  size;
         int  flags;
 } svr4_stack_t;
diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
--- a/include/asm-sparc64/unistd.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-sparc64/unistd.h	Sat Apr  3 19:38:41 2004
@@ -443,11 +443,12 @@
 static __inline__ _syscall1(int,_exit,int,exitcode)
 static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
 
+#include <linux/linkage.h>
+
 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 -Nru a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
--- a/include/asm-um/processor-generic.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-um/processor-generic.h	Sat Apr  3 19:38:41 2004
@@ -94,8 +94,6 @@
 	.request		= { 0 } \
 }
 
-#define INIT_THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
-
 typedef struct {
 	unsigned long seg;
 } mm_segment_t;
diff -Nru a/include/asm-v850/pci.h b/include/asm-v850/pci.h
--- a/include/asm-v850/pci.h	Sat Apr  3 19:38:42 2004
+++ b/include/asm-v850/pci.h	Sat Apr  3 19:38:42 2004
@@ -27,7 +27,7 @@
 
 /* `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 @@
    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 -Nru a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
--- a/include/asm-x86_64/acpi.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-x86_64/acpi.h	Sat Apr  3 19:38:45 2004
@@ -60,7 +60,7 @@
 	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 @@
 	do {
 		old = *lock;
 		new = old & ~0x3;
-		val = cmpxchg4_locked(lock, new, old);
+		val = cmpxchg(lock, old, new);
 	} while (unlikely (val != old));
 	return old & 0x1;
 }
@@ -105,9 +105,14 @@
 extern int acpi_ioapic;
 extern int acpi_noirq;
 extern int acpi_strict;
+extern int acpi_disabled;
+extern int acpi_ht;
+static inline void disable_acpi(void) { acpi_disabled = 1; acpi_ht = 0; }
 
 /* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
 #define FIX_ACPI_PAGES 4
+
+extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq);
 
 #else	/* !CONFIG_ACPI_BOOT */
 #define acpi_lapic 0
diff -Nru a/include/asm-x86_64/bitops.h b/include/asm-x86_64/bitops.h
--- a/include/asm-x86_64/bitops.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-x86_64/bitops.h	Sat Apr  3 19:38:43 2004
@@ -503,6 +503,8 @@
 /* find last set bit */
 #define fls(x) generic_fls(x)
 
+#define ARCH_HAS_ATOMIC_UNSIGNED 1
+
 #endif /* __KERNEL__ */
 
 #endif /* _X86_64_BITOPS_H */
diff -Nru a/include/asm-x86_64/calling.h b/include/asm-x86_64/calling.h
--- a/include/asm-x86_64/calling.h	Sat Apr  3 19:38:45 2004
+++ b/include/asm-x86_64/calling.h	Sat Apr  3 19:38:45 2004
@@ -31,41 +31,47 @@
 #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) 
-	CFI_OFFSET	rdi,8*8-(9*8+\addskip)
+	CFI_REL_OFFSET	rdi,8*8
 	movq  %rsi,7*8(%rsp) 
-	CFI_OFFSET	rsi,7*8-(9*8+\addskip)
+	CFI_REL_OFFSET	rsi,7*8
 	movq  %rdx,6*8(%rsp)
-	CFI_OFFSET	rdx,6*8-(9*8+\addskip)
+	CFI_REL_OFFSET	rdx,6*8
 	.if \norcx
 	.else
 	movq  %rcx,5*8(%rsp)
-	CFI_OFFSET	rcx,5*8-(9*8+\addskip)
+	CFI_REL_OFFSET	rcx,5*8
 	.endif
 	movq  %rax,4*8(%rsp) 
-	CFI_OFFSET	rax,4*8-(9*8+\addskip)
+	CFI_REL_OFFSET	rax,4*8
+	.if \nor891011
+	.else
 	movq  %r8,3*8(%rsp) 
-	CFI_OFFSET	r8,3*8-(9*8+\addskip)
+	CFI_REL_OFFSET	r8,3*8
 	movq  %r9,2*8(%rsp) 
-	CFI_OFFSET	r9,2*8-(9*8+\addskip)
+	CFI_REL_OFFSET	r9,2*8
 	movq  %r10,1*8(%rsp) 
-	CFI_OFFSET	r10,1*8-(9*8+\addskip)
+	CFI_REL_OFFSET	r10,1*8
 	movq  %r11,(%rsp) 
-	CFI_OFFSET	r11,-(9*8+\addskip)
+	CFI_REL_OFFSET	r11,0*8
+	.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
@@ -100,17 +109,17 @@
 	subq $REST_SKIP,%rsp
 	CFI_ADJUST_CFA_OFFSET	REST_SKIP
 	movq %rbx,5*8(%rsp) 
-	CFI_OFFSET	rbx,5*8-(REST_SKIP)
+	CFI_REL_OFFSET	rbx,5*8
 	movq %rbp,4*8(%rsp) 
-	CFI_OFFSET	rbp,4*8-(REST_SKIP)
+	CFI_REL_OFFSET	rbp,4*8
 	movq %r12,3*8(%rsp) 
-	CFI_OFFSET	r12,3*8-(REST_SKIP)
+	CFI_REL_OFFSET	r12,3*8
 	movq %r13,2*8(%rsp) 
-	CFI_OFFSET	r13,2*8-(REST_SKIP)
+	CFI_REL_OFFSET	r13,2*8
 	movq %r14,1*8(%rsp) 
-	CFI_OFFSET	r14,1*8-(REST_SKIP)
+	CFI_REL_OFFSET	r14,1*8
 	movq %r15,(%rsp) 
-	CFI_OFFSET	r15,0*8-(REST_SKIP)
+	CFI_REL_OFFSET	r15,0*8
 	.endm		
 
 	.macro RESTORE_REST
diff -Nru a/include/asm-x86_64/compat.h b/include/asm-x86_64/compat.h
--- a/include/asm-x86_64/compat.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-x86_64/compat.h	Sat Apr  3 19:38:54 2004
@@ -29,6 +29,7 @@
 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;
@@ -118,6 +119,64 @@
 
 #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
diff -Nru a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h
--- a/include/asm-x86_64/hardirq.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-x86_64/hardirq.h	Sat Apr  3 19:38:41 2004
@@ -78,6 +78,7 @@
 
 
 #ifdef CONFIG_PREEMPT
+# include <linux/smp_lock.h>
 # define in_atomic()   ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-x86_64/hpet.h b/include/asm-x86_64/hpet.h
--- a/include/asm-x86_64/hpet.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-x86_64/hpet.h	Sat Apr  3 19:38:55 2004
@@ -1,8 +1,6 @@
 #ifndef _ASM_X8664_HPET_H
 #define _ASM_X8664_HPET_H 1
 
-#include <linux/interrupt.h>
-
 /*
  * Documentation on HPET can be found at:
  *      http://www.intel.com/ial/home/sp/pcmmspec.htm
@@ -53,7 +51,6 @@
 extern int hpet_set_periodic_freq(unsigned long freq);
 extern int hpet_rtc_dropped_irq(void);
 extern int hpet_rtc_timer_init(void);
-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 #endif /* CONFIG_HPET_EMULATE_RTC */
 
 #endif
diff -Nru a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
--- a/include/asm-x86_64/io.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-x86_64/io.h	Sat Apr  3 19:38:43 2004
@@ -109,17 +109,6 @@
 
 #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 @@
  * 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 @@
 #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 @@
 
 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 @@
  * 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 -Nru a/include/asm-x86_64/mpspec.h b/include/asm-x86_64/mpspec.h
--- a/include/asm-x86_64/mpspec.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-x86_64/mpspec.h	Sat Apr  3 19:38:43 2004
@@ -186,14 +186,12 @@
 extern void mp_register_lapic_address (u64 address);
 
 #ifdef CONFIG_X86_IO_APIC
-extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base);
-extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq);
+extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
+extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
 extern void mp_config_acpi_legacy_irqs (void);
 extern void mp_parse_prt (void);
 #endif /*CONFIG_X86_IO_APIC*/
 #endif
-
-extern void mp_config_ioapic_for_sci(int irq);
 
 extern int using_apic_timer;
 
diff -Nru a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
--- a/include/asm-x86_64/msr.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-x86_64/msr.h	Sat Apr  3 19:38:55 2004
@@ -156,6 +156,10 @@
 #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 -Nru a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
--- a/include/asm-x86_64/page.h	Sat Apr  3 19:38:41 2004
+++ b/include/asm-x86_64/page.h	Sat Apr  3 19:38:41 2004
@@ -137,6 +137,13 @@
 #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 -Nru a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
--- a/include/asm-x86_64/pci.h	Sat Apr  3 19:38:43 2004
+++ b/include/asm-x86_64/pci.h	Sat Apr  3 19:38:43 2004
@@ -49,7 +49,7 @@
 extern int iommu_setup(char *opt);
 
 extern dma_addr_t bad_dma_address;
-#define pci_dma_error(x) ((x) == bad_dma_address)
+#define pci_dma_mapping_error(x) ((x) == bad_dma_address)
 
 /* Allocate and map kernel buffer using consistent mode DMA for a device.
  * hwdev should be valid struct pci_dev pointer for PCI devices,
@@ -78,10 +78,18 @@
 				      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 @@
  * 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 @@
 #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 @@
  * 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 @@
 /* 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 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 -Nru a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
--- a/include/asm-x86_64/processor.h	Sat Apr  3 19:38:56 2004
+++ b/include/asm-x86_64/processor.h	Sat Apr  3 19:38:56 2004
@@ -173,7 +173,7 @@
  * 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 @@
 #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 
 
@@ -450,5 +452,7 @@
 	asm("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK));	\
 	ti->task;					\
 })
+
+#define cache_line_size() (boot_cpu_data.x86_clflush_size)
 
 #endif /* __ASM_X86_64_PROCESSOR_H */
diff -Nru a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
--- a/include/asm-x86_64/proto.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-x86_64/proto.h	Sat Apr  3 19:38:55 2004
@@ -21,6 +21,7 @@
 
 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 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 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 -Nru a/include/asm-x86_64/siginfo.h b/include/asm-x86_64/siginfo.h
--- a/include/asm-x86_64/siginfo.h	Sat Apr  3 19:38:57 2004
+++ b/include/asm-x86_64/siginfo.h	Sat Apr  3 19:38:57 2004
@@ -3,8 +3,6 @@
 
 #define __ARCH_SI_PREAMBLE_SIZE	(4 * sizeof(int))
 
-#define __ARCH_SI_BAND_T long
-
 #define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 4)
 
 #include <asm-generic/siginfo.h>
diff -Nru a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
--- a/include/asm-x86_64/smp.h	Sat Apr  3 19:38:40 2004
+++ b/include/asm-x86_64/smp.h	Sat Apr  3 19:38:40 2004
@@ -47,7 +47,8 @@
 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[];
+extern char phys_proc_id[NR_CPUS];
 
 #define SMP_TRAMPOLINE_BASE 0x6000
 
@@ -74,7 +75,15 @@
 	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 -Nru a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
--- a/include/asm-x86_64/system.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-x86_64/system.h	Sat Apr  3 19:38:55 2004
@@ -276,13 +276,6 @@
 	((__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 -Nru a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
--- a/include/asm-x86_64/thread_info.h	Sat Apr  3 19:38:54 2004
+++ b/include/asm-x86_64/thread_info.h	Sat Apr  3 19:38:54 2004
@@ -82,7 +82,6 @@
 #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
@@ -118,8 +117,10 @@
 #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_SINGLESTEP))
+/* work to do on any return to user space */
+#define _TIF_ALLWORK_MASK 0x0000FFFF	
 
 #define PREEMPT_ACTIVE     0x4000000
 
diff -Nru a/include/asm-x86_64/types.h b/include/asm-x86_64/types.h
--- a/include/asm-x86_64/types.h	Sat Apr  3 19:38:55 2004
+++ b/include/asm-x86_64/types.h	Sat Apr  3 19:38:55 2004
@@ -33,6 +33,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/config.h>
+
 typedef signed char s8;
 typedef unsigned char u8;
 
diff -Nru a/include/asm-x86_64/vsyscall32.h b/include/asm-x86_64/vsyscall32.h
--- a/include/asm-x86_64/vsyscall32.h	Sat Apr  3 19:38:44 2004
+++ b/include/asm-x86_64/vsyscall32.h	Sat Apr  3 19:38:44 2004
@@ -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 -Nru a/include/linux/aio.h b/include/linux/aio.h
--- a/include/linux/aio.h	Sat Apr  3 19:38:40 2004
+++ b/include/linux/aio.h	Sat Apr  3 19:38:40 2004
@@ -59,7 +59,7 @@
 	struct list_head	ki_list;	/* the aio core uses this
 						 * for cancellation */
 
-	void			*ki_user_obj;	/* pointer to userland's iocb */
+	void __user		*ki_user_obj;	/* pointer to userland's iocb */
 	__u64			ki_user_data;	/* user's data for completion */
 	loff_t			ki_pos;
 
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Sat Apr  3 19:38:42 2004
+++ b/include/linux/blkdev.h	Sat Apr  3 19:38:42 2004
@@ -517,6 +517,9 @@
 extern void __blk_stop_queue(request_queue_t *q);
 extern void blk_run_queue(request_queue_t *q);
 extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
+extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int);
+extern int blk_rq_unmap_user(struct request *, void __user *, unsigned int);
+extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *);
 
 static inline request_queue_t *bdev_get_queue(struct block_device *bdev)
 {
@@ -589,7 +592,7 @@
 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 -Nru a/include/linux/brlvger.h b/include/linux/brlvger.h
--- a/include/linux/brlvger.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/include/linux/cdrom.h b/include/linux/cdrom.h
--- a/include/linux/cdrom.h	Sat Apr  3 19:38:40 2004
+++ b/include/linux/cdrom.h	Sat Apr  3 19:38:40 2004
@@ -722,7 +722,9 @@
 /*
  * feature profile
  */
-#define CDF_MRW		0x28
+#define CDF_RWRT	0x0020	/* "Random Writable" */
+#define CDF_HWDM	0x0024	/* "Hardware Defect Management" */
+#define CDF_MRW 	0x0028
 
 /*
  * media status bits
@@ -771,6 +773,34 @@
 	__u8 reserved5;
 };
 
+/* cf. mmc4r02g.pdf 5.3.10 Random Writable Feature (0020h) pg 197 of 635 */
+struct rwrt_feature_desc {
+	__u16 feature_code;
+#if defined(__BIG_ENDIAN_BITFIELD)
+	__u8 reserved1		: 2;
+	__u8 feature_version	: 4;
+	__u8 persistent		: 1;
+	__u8 curr		: 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 curr		: 1;
+	__u8 persistent		: 1;
+	__u8 feature_version	: 4;
+	__u8 reserved1		: 2;
+#endif
+	__u8 add_len;
+	__u32 last_lba;
+	__u32 block_size;
+	__u16 blocking;
+#if defined(__BIG_ENDIAN_BITFIELD)
+	__u8 reserved2		: 7;
+	__u8 page_present	: 1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	__u8 page_present	: 1;
+	__u8 reserved2		: 7;
+#endif
+	__u8 reserved3;
+};
+
 typedef struct {
 	__u16 disc_information_length;
 #if defined(__BIG_ENDIAN_BITFIELD)
@@ -877,10 +907,18 @@
 #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 +932,8 @@
 /* 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;
@@ -1130,6 +1170,7 @@
 
 extern int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med);
 extern int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write);
+extern int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write);
 
 #endif  /* End of kernel only stuff */ 
 
diff -Nru a/include/linux/compat.h b/include/linux/compat.h
--- a/include/linux/compat.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/compat.h	Sat Apr  3 19:38:43 2004
@@ -10,6 +10,8 @@
 
 #include <linux/stat.h>
 #include <linux/param.h>	/* for HZ */
+#include <linux/sem.h>
+
 #include <asm/compat.h>
 
 #define compat_jiffies_to_clock_t(x)	\
@@ -88,5 +90,15 @@
 	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 -Nru a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
--- a/include/linux/compat_ioctl.h	Sat Apr  3 19:38:56 2004
+++ b/include/linux/compat_ioctl.h	Sat Apr  3 19:38:56 2004
@@ -48,6 +48,7 @@
 COMPATIBLE_IOCTL(TIOCSPTLCK)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
 /* Big F */
+COMPATIBLE_IOCTL(FBIOBLANK)
 COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
 COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
 COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
@@ -134,6 +135,7 @@
 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)
@@ -246,10 +248,6 @@
 COMPATIBLE_IOCTL(SIOCSIFENCAP)
 COMPATIBLE_IOCTL(SIOCGIFENCAP)
 COMPATIBLE_IOCTL(SIOCSIFNAME)
-/* FIXME: not compatible
-COMPATIBLE_IOCTL(SIOCSIFBR)
-COMPATIBLE_IOCTL(SIOCGIFBR)
-*/
 COMPATIBLE_IOCTL(SIOCSARP)
 COMPATIBLE_IOCTL(SIOCGARP)
 COMPATIBLE_IOCTL(SIOCDARP)
@@ -616,6 +614,10 @@
 COMPATIBLE_IOCTL(BNEPCONNDEL)
 COMPATIBLE_IOCTL(BNEPGETCONNLIST)
 COMPATIBLE_IOCTL(BNEPGETCONNINFO)
+COMPATIBLE_IOCTL(CMTPCONNADD)
+COMPATIBLE_IOCTL(CMTPCONNDEL)
+COMPATIBLE_IOCTL(CMTPGETCONNLIST)
+COMPATIBLE_IOCTL(CMTPGETCONNINFO)
 /* Misc. */
 COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
 COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
diff -Nru a/include/linux/compiler.h b/include/linux/compiler.h
--- a/include/linux/compiler.h	Sat Apr  3 19:38:45 2004
+++ b/include/linux/compiler.h	Sat Apr  3 19:38:45 2004
@@ -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.
@@ -99,19 +113,5 @@
 #ifndef noinline
 #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 -Nru a/include/linux/cpu.h b/include/linux/cpu.h
--- a/include/linux/cpu.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/cpu.h	Sat Apr  3 19:38:41 2004
@@ -63,6 +63,7 @@
 	static struct notifier_block fn##_nb = { fn, pri };	\
 	register_cpu_notifier(&fn##_nb);			\
 }
+int cpu_down(unsigned int cpu);
 #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
 #else
 #define lock_cpu_hotplug()	do { } while (0)
diff -Nru a/include/linux/crypto.h b/include/linux/crypto.h
--- a/include/linux/crypto.h	Sat Apr  3 19:38:42 2004
+++ b/include/linux/crypto.h	Sat Apr  3 19:38:42 2004
@@ -76,6 +76,8 @@
 	void (*dia_init)(void *ctx);
 	void (*dia_update)(void *ctx, const u8 *data, unsigned int len);
 	void (*dia_final)(void *ctx, u8 *out);
+	int (*dia_setkey)(void *ctx, const u8 *key,
+	                  unsigned int keylen, u32 *flags);
 };
 
 struct compress_alg {
@@ -157,6 +159,8 @@
 	void (*dit_final)(struct crypto_tfm *tfm, u8 *out);
 	void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg,
 	                   unsigned int nsg, u8 *out);
+	int (*dit_setkey)(struct crypto_tfm *tfm,
+	                  const u8 *key, unsigned int keylen);
 #ifdef CONFIG_CRYPTO_HMAC
 	void *dit_hmac_block;
 #endif
@@ -280,6 +284,15 @@
 {
 	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
 	tfm->crt_digest.dit_digest(tfm, sg, nsg, out);
+}
+
+static inline int crypto_digest_setkey(struct crypto_tfm *tfm,
+                                       const u8 *key, unsigned int keylen)
+{
+	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
+	if (tfm->crt_digest.dit_setkey == NULL)
+		return -ENOSYS;
+	return tfm->crt_digest.dit_setkey(tfm, key, keylen);
 }
 
 static inline int crypto_cipher_setkey(struct crypto_tfm *tfm,
diff -Nru a/include/linux/device-mapper.h b/include/linux/device-mapper.h
--- a/include/linux/device-mapper.h	Sat Apr  3 19:38:45 2004
+++ b/include/linux/device-mapper.h	Sat Apr  3 19:38:45 2004
@@ -13,6 +13,11 @@
 
 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 @@
  * = 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 @@
 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 @@
 	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 -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Sat Apr  3 19:38:55 2004
+++ b/include/linux/device.h	Sat Apr  3 19:38:55 2004
@@ -285,6 +285,12 @@
 					   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 -Nru a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
--- a/include/linux/dm-ioctl.h	Sat Apr  3 19:38:40 2004
+++ b/include/linux/dm-ioctl.h	Sat Apr  3 19:38:40 2004
@@ -163,6 +163,16 @@
 };
 
 /*
+ * 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 @@
 	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 @@
 #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 -Nru a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
--- a/include/linux/dma-mapping.h	Sat Apr  3 19:38:55 2004
+++ b/include/linux/dma-mapping.h	Sat Apr  3 19:38:55 2004
@@ -12,6 +12,10 @@
 
 #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 -Nru a/include/linux/edd.h b/include/linux/edd.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/edd.h	Sat Apr  3 19:38:41 2004
@@ -0,0 +1,181 @@
+/*
+ * linux/include/linux/edd.h
+ *  Copyright (C) 2002, 2003 Dell Inc.
+ *  by Matt Domsch <Matt_Domsch@dell.com>
+ *
+ * structures and definitions for the int 13h, ax={41,48}h
+ * BIOS Enhanced Disk Drive Services
+ * This is based on the T13 group document D1572 Revision 0 (August 14 2002)
+ * available at http://www.t13.org/docs2002/d1572r0.pdf.  It is
+ * very similar to D1484 Revision 3 http://www.t13.org/docs2002/d1484r3.pdf
+ *
+ * In a nutshell, arch/{i386,x86_64}/boot/setup.S populates a scratch table
+ * in the empty_zero_block that contains a list of BIOS-enumerated
+ * boot devices.
+ * In arch/{i386,x86_64}/kernel/setup.c, this information is
+ * transferred into the edd structure, and in drivers/firmware/edd.c, that
+ * information is used to identify BIOS boot disk.  The code in setup.S
+ * is very sensitive to the size of these structures.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * 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.
+ *
+ */
+#ifndef _LINUX_EDD_H
+#define _LINUX_EDD_H
+
+#define EDDNR 0x1e9		/* addr of number of edd_info structs at EDDBUF
+				   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 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
+
+#define READ_SECTORS 0x02
+#define MBR_SIG_OFFSET 0x1B8
+#define DISK80_SIG_BUFFER 0x2cc
+#ifndef __ASSEMBLY__
+
+#define EDD_EXT_FIXED_DISK_ACCESS           (1 << 0)
+#define EDD_EXT_DEVICE_LOCKING_AND_EJECTING (1 << 1)
+#define EDD_EXT_ENHANCED_DISK_DRIVE_SUPPORT (1 << 2)
+#define EDD_EXT_64BIT_EXTENSIONS            (1 << 3)
+
+#define EDD_INFO_DMA_BOUNDARY_ERROR_TRANSPARENT (1 << 0)
+#define EDD_INFO_GEOMETRY_VALID                (1 << 1)
+#define EDD_INFO_REMOVABLE                     (1 << 2)
+#define EDD_INFO_WRITE_VERIFY                  (1 << 3)
+#define EDD_INFO_MEDIA_CHANGE_NOTIFICATION     (1 << 4)
+#define EDD_INFO_LOCKABLE                      (1 << 5)
+#define EDD_INFO_NO_MEDIA_PRESENT              (1 << 6)
+#define EDD_INFO_USE_INT13_FN50                (1 << 7)
+
+struct edd_device_params {
+	u16 length;
+	u16 info_flags;
+	u32 num_default_cylinders;
+	u32 num_default_heads;
+	u32 sectors_per_track;
+	u64 number_of_sectors;
+	u16 bytes_per_sector;
+	u32 dpte_ptr;		/* 0xFFFFFFFF for our purposes */
+	u16 key;		/* = 0xBEDD */
+	u8 device_path_info_length;	/* = 44 */
+	u8 reserved2;
+	u16 reserved3;
+	u8 host_bus_type[4];
+	u8 interface_type[8];
+	union {
+		struct {
+			u16 base_address;
+			u16 reserved1;
+			u32 reserved2;
+		} __attribute__ ((packed)) isa;
+		struct {
+			u8 bus;
+			u8 slot;
+			u8 function;
+			u8 channel;
+			u32 reserved;
+		} __attribute__ ((packed)) pci;
+		/* pcix is same as pci */
+		struct {
+			u64 reserved;
+		} __attribute__ ((packed)) ibnd;
+		struct {
+			u64 reserved;
+		} __attribute__ ((packed)) xprs;
+		struct {
+			u64 reserved;
+		} __attribute__ ((packed)) htpt;
+		struct {
+			u64 reserved;
+		} __attribute__ ((packed)) unknown;
+	} interface_path;
+	union {
+		struct {
+			u8 device;
+			u8 reserved1;
+			u16 reserved2;
+			u32 reserved3;
+			u64 reserved4;
+		} __attribute__ ((packed)) ata;
+		struct {
+			u8 device;
+			u8 lun;
+			u8 reserved1;
+			u8 reserved2;
+			u32 reserved3;
+			u64 reserved4;
+		} __attribute__ ((packed)) atapi;
+		struct {
+			u16 id;
+			u64 lun;
+			u16 reserved1;
+			u32 reserved2;
+		} __attribute__ ((packed)) scsi;
+		struct {
+			u64 serial_number;
+			u64 reserved;
+		} __attribute__ ((packed)) usb;
+		struct {
+			u64 eui;
+			u64 reserved;
+		} __attribute__ ((packed)) i1394;
+		struct {
+			u64 wwid;
+			u64 lun;
+		} __attribute__ ((packed)) fibre;
+		struct {
+			u64 identity_tag;
+			u64 reserved;
+		} __attribute__ ((packed)) i2o;
+		struct {
+			u32 array_number;
+			u32 reserved1;
+			u64 reserved2;
+		} __attribute__ ((packed)) raid;
+		struct {
+			u8 device;
+			u8 reserved1;
+			u16 reserved2;
+			u32 reserved3;
+			u64 reserved4;
+		} __attribute__ ((packed)) sata;
+		struct {
+			u64 reserved1;
+			u64 reserved2;
+		} __attribute__ ((packed)) unknown;
+	} device_path;
+	u8 reserved4;
+	u8 checksum;
+} __attribute__ ((packed));
+
+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));
+
+extern struct edd_info edd[EDDMAXNR];
+extern unsigned char eddnr;
+extern unsigned int edd_disk80_sig;
+
+#endif				/*!__ASSEMBLY__ */
+
+#endif				/* _LINUX_EDD_H */
diff -Nru a/include/linux/fb.h b/include/linux/fb.h
--- a/include/linux/fb.h	Sat Apr  3 19:38:42 2004
+++ b/include/linux/fb.h	Sat Apr  3 19:38:42 2004
@@ -236,15 +236,71 @@
 #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 @@
 	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 @@
 	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_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 @@
 #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 @@
 #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 @@
 #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 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 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 -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Sat Apr  3 19:38:42 2004
+++ b/include/linux/fs.h	Sat Apr  3 19:38:42 2004
@@ -89,6 +89,7 @@
 
 /* public flags for file_system_type */
 #define FS_REQUIRES_DEV 1 
+#define FS_BINARY_MOUNTDATA 2
 #define FS_REVAL_DOT	16384	/* Check the paths ".", ".." for staleness */
 #define FS_ODD_RENAME	32768	/* Temporary stuff; will go away as soon
 				  * as nfs_rename() will be cleaned up
@@ -137,6 +138,7 @@
 #define S_DEAD		32	/* removed, but still open directory */
 #define S_NOQUOTA	64	/* Inode is not counted to quota */
 #define S_DIRSYNC	128	/* Directory modifications are synchronous */
+#define S_NOCMTIME	256	/* Do not update file c/mtime */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -170,6 +172,7 @@
 #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. */
@@ -330,7 +333,6 @@
 	struct list_head	i_mmap_shared;	/* list of shared mappings */
 	struct semaphore	i_shared_sem;	/* protect both above lists */
 	atomic_t		truncate_count;	/* Cover race condition with truncate */
-	unsigned long		dirtied_when;	/* jiffies of first page dirtying */
 	unsigned long		flags;		/* error bits/gfp mask */
 	struct backing_dev_info *backing_dev_info; /* device readahead, etc */
 	spinlock_t		private_lock;	/* for use by the address_space */
@@ -413,6 +415,7 @@
 	struct dnotify_struct	*i_dnotify; /* for directory notifications */
 
 	unsigned long		i_state;
+	unsigned long		dirtied_when;	/* jiffies of first dirtying */
 
 	unsigned int		i_flags;
 	unsigned char		i_sock;
@@ -507,6 +510,8 @@
 	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 */
@@ -909,6 +914,17 @@
 	__mark_inode_dirty(inode, I_DIRTY_SYNC);
 }
 
+static inline void touch_atime(struct vfsmount *mnt, struct dentry *dentry)
+{
+	/* per-mountpoint checks will go here */
+	update_atime(dentry->d_inode);
+}
+
+static inline void file_accessed(struct file *file)
+{
+	touch_atime(file->f_vfsmnt, file->f_dentry);
+}
+
 
 /**
  * &export_operations - for nfsd to communicate with file systems
@@ -1133,6 +1149,7 @@
 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 *);
@@ -1280,7 +1297,7 @@
 extern void clear_inode(struct inode *);
 extern void destroy_inode(struct inode *);
 extern struct inode *new_inode(struct super_block *);
-extern void remove_suid(struct dentry *);
+extern int remove_suid(struct dentry *);
 
 extern void __insert_inode_hash(struct inode *, unsigned long hashval);
 extern void remove_inode_hash(struct inode *);
@@ -1315,7 +1332,8 @@
 ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
 				unsigned long nr_segs, loff_t *ppos);
 extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void __user *);
-extern void do_generic_mapping_read(struct address_space *, struct file_ra_state *, struct file *,
+extern void do_generic_mapping_read(struct address_space *mapping,
+				    struct file_ra_state *, struct file *,
 				    loff_t *, read_descriptor_t *, read_actor_t);
 extern void
 file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
diff -Nru a/include/linux/hiddev.h b/include/linux/hiddev.h
--- a/include/linux/hiddev.h	Sat Apr  3 19:38:42 2004
+++ b/include/linux/hiddev.h	Sat Apr  3 19:38:42 2004
@@ -39,33 +39,33 @@
 };
 
 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 @@
 #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 @@
 #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 
@@ -160,6 +168,10 @@
 #define HIDIOCGCOLLECTIONINDEX	_IOW('H', 0x10, 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 -Nru a/include/linux/hpfs_fs_i.h b/include/linux/hpfs_fs_i.h
--- a/include/linux/hpfs_fs_i.h	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,24 +0,0 @@
-#ifndef _HPFS_FS_I
-#define _HPFS_FS_I
-
-struct hpfs_inode_info {
-	loff_t mmu_private;
-	ino_t i_parent_dir;	/* (directories) gives fnode of parent dir */
-	unsigned i_dno;		/* (directories) root dnode */
-	unsigned i_dpos;	/* (directories) temp for readdir */
-	unsigned i_dsubdno;	/* (directories) temp for readdir */
-	unsigned i_file_sec;	/* (files) minimalist cache of alloc info */
-	unsigned i_disk_sec;	/* (files) minimalist cache of alloc info */
-	unsigned i_n_secs;	/* (files) minimalist cache of alloc info */
-	unsigned i_ea_size;	/* size of extended attributes */
-	unsigned i_conv : 2;	/* (files) crlf->newline hackery */
-	unsigned i_ea_mode : 1;	/* file's permission is stored in ea */
-	unsigned i_ea_uid : 1;	/* file's uid is stored in ea */
-	unsigned i_ea_gid : 1;	/* file's gid is stored in ea */
-	unsigned i_dirty : 1;
-	struct semaphore i_sem;	/* semaphore */
-	loff_t **i_rddir_off;
-	struct inode vfs_inode;
-};
-
-#endif
diff -Nru a/include/linux/hpfs_fs_sb.h b/include/linux/hpfs_fs_sb.h
--- a/include/linux/hpfs_fs_sb.h	Sat Apr  3 19:38:55 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,39 +0,0 @@
-#ifndef _HPFS_FS_SB
-#define _HPFS_FS_SB
-
-struct hpfs_sb_info {
-	ino_t sb_root;			/* inode number of root dir */
-	unsigned sb_fs_size;		/* file system size, sectors */
-	unsigned sb_bitmaps;		/* sector number of bitmap list */
-	unsigned sb_dirband_start;	/* directory band start sector */
-	unsigned sb_dirband_size;	/* directory band size, dnodes */
-	unsigned sb_dmap;		/* sector number of dnode bit map */
-	unsigned sb_n_free;		/* free blocks for statfs, or -1 */
-	unsigned sb_n_free_dnodes;	/* free dnodes for statfs, or -1 */
-	uid_t sb_uid;			/* uid from mount options */
-	gid_t sb_gid;			/* gid from mount options */
-	umode_t sb_mode;		/* mode from mount options */
-	unsigned sb_conv : 2;		/* crlf->newline hackery */
-	unsigned sb_eas : 2;		/* eas: 0-ignore, 1-ro, 2-rw */
-	unsigned sb_err : 2;		/* on errs: 0-cont, 1-ro, 2-panic */
-	unsigned sb_chk : 2;		/* checks: 0-no, 1-normal, 2-strict */
-	unsigned sb_lowercase : 1;	/* downcase filenames hackery */
-	unsigned sb_was_error : 1;	/* there was an error, set dirty flag */
-	unsigned sb_chkdsk : 2;		/* chkdsk: 0-no, 1-on errs, 2-allways */
-	unsigned sb_rd_fnode : 2;	/* read fnode 0-no 1-dirs 2-all */
-	unsigned sb_rd_inode : 2;	/* lookup tells read_inode: 1-read fnode
-					   2-don't read fnode, file
-					   3-don't read fnode, direcotry */
-	wait_queue_head_t sb_iget_q;
-	unsigned char *sb_cp_table;	/* code page tables: */
-					/* 	128 bytes uppercasing table & */
-					/*	128 bytes lowercasing table */
-	unsigned *sb_bmp_dir;		/* main bitmap directory */
-	unsigned sb_c_bitmap;		/* current bitmap */
-	struct semaphore hpfs_creation_de; /* when creating dirents, nobody else
-					   can alloc blocks */
-	/*unsigned sb_mounting : 1;*/
-	int sb_timeshift;
-};
-
-#endif
diff -Nru a/include/linux/hugetlb.h b/include/linux/hugetlb.h
--- a/include/linux/hugetlb.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/hugetlb.h	Sat Apr  3 19:38:43 2004
@@ -19,6 +19,7 @@
 void huge_page_release(struct page *);
 int hugetlb_report_meminfo(char *);
 int is_hugepage_mem_enough(size_t);
+unsigned long hugetlb_total_pages(void);
 struct page *follow_huge_addr(struct mm_struct *mm, struct vm_area_struct *vma,
 			unsigned long address, int write);
 struct vm_area_struct *hugepage_vma(struct mm_struct *mm,
@@ -42,12 +43,23 @@
 #define hugetlb_free_pgtables(tlb, prev, start, end) do { } while (0)
 #endif
 
+#ifndef ARCH_HAS_PREPARE_HUGEPAGE_RANGE
+#define prepare_hugepage_range(addr, len)	\
+	is_aligned_hugepage_range(addr, len)
+#else
+int prepare_hugepage_range(unsigned long addr, unsigned long len);
+#endif
+
 #else /* !CONFIG_HUGETLB_PAGE */
 
 static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
 {
 	return 0;
 }
+static inline unsigned long hugetlb_total_pages(void)
+{
+	return 0;
+}
 
 #define follow_hugetlb_page(m,v,p,vs,a,b,i)	({ BUG(); 0; })
 #define follow_huge_addr(mm, vma, addr, write)	0
@@ -62,6 +74,7 @@
 #define mark_mm_hugetlb(mm, vma)		do { } while (0)
 #define follow_huge_pmd(mm, addr, pmd, write)	0
 #define is_aligned_hugepage_range(addr, len)	0
+#define prepare_hugepage_range(addr, len)	(-EINVAL)
 #define pmd_huge(x)	0
 #define is_hugepage_only_range(addr, len)	0
 #define hugetlb_free_pgtables(tlb, prev, start, end) do { } while (0)
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Sat Apr  3 19:38:42 2004
+++ b/include/linux/ide.h	Sat Apr  3 19:38:42 2004
@@ -24,8 +24,6 @@
 #include <asm/io.h>
 #include <asm/semaphore.h>
 
-#define DEBUG_PM
-
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
  * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
@@ -143,17 +141,8 @@
 #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 +154,6 @@
 #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
@@ -761,8 +740,6 @@
 
 	u64		capacity64;	/* total number of sectors */
 
-	int		last_lun;	/* last logical unit */
-	int		forced_lun;	/* if hdxlun was given at boot */
 	int		lun;		/* logical unit */
 	int		crc_count;	/* crc counter to reduce drive speed */
 	struct list_head list;
@@ -870,8 +847,6 @@
 
 	struct pci_dev  *pci_dev;	/* for pci chipsets */
 	struct ide_pci_device_s	*cds;	/* chipset device struct */
-	
-	struct pnp_dev  *pnp_dev;	/* for PnP devices */
 
 	ide_startstop_t (*rw_disk)(ide_drive_t *, struct request *, sector_t);
 
@@ -953,10 +928,9 @@
 	int sg_dma_direction;		/* dma transfer direction */
 	int sg_dma_active;		/* is it in use */
 
-	int		mmio;		/* hosts iomio (0), mmio (1) or custom (2) select */
+	int		mmio;		/* hosts iomio (0) or custom (2) select */
 	int		rqsize;		/* max sectors per request */
 	int		irq;		/* our irq number */
-	int		initializing;	/* set while initializing self */
 
 	unsigned long	dma_master;	/* reference base addr dmabase */
 	unsigned long	dma_base;	/* base addr for dma ports */
@@ -998,7 +972,6 @@
  */
 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 +1333,6 @@
 	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;
@@ -1455,19 +1427,9 @@
 extern ide_startstop_t task_out_intr(ide_drive_t *);
 extern ide_startstop_t pre_task_mulout_intr(ide_drive_t *, struct request *);
 extern ide_startstop_t task_mulout_intr(ide_drive_t *);
-extern void ide_init_drive_taskfile(struct request *);
 
 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 +1605,7 @@
 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 -Nru a/include/linux/init.h b/include/linux/init.h
--- a/include/linux/init.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/init.h	Sat Apr  3 19:38:41 2004
@@ -110,12 +110,21 @@
 };
 
 /* 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 @@
 	{ 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 -Nru a/include/linux/interrupt.h b/include/linux/interrupt.h
--- a/include/linux/interrupt.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/interrupt.h	Sat Apr  3 19:38:43 2004
@@ -211,6 +211,7 @@
 }
 
 extern void tasklet_kill(struct tasklet_struct *t);
+extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
 extern void tasklet_init(struct tasklet_struct *t,
 			 void (*func)(unsigned long), unsigned long data);
 
diff -Nru a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
--- a/include/linux/kernel_stat.h	Sat Apr  3 19:38:56 2004
+++ b/include/linux/kernel_stat.h	Sat Apr  3 19:38:56 2004
@@ -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 @@
 /* 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 -Nru a/include/linux/kobject.h b/include/linux/kobject.h
--- a/include/linux/kobject.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/kobject.h	Sat Apr  3 19:38:41 2004
@@ -151,6 +151,14 @@
 		.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 -Nru a/include/linux/kref.h b/include/linux/kref.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/kref.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,32 @@
+/*
+ * kref.c - library routines for handling generic reference counted objects
+ *
+ * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2004 IBM Corp.
+ *
+ * based on kobject.h which was:
+ * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org>
+ * Copyright (C) 2002-2003 Open Source Development Labs
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#if defined(__KERNEL__) && !defined(_KREF_H_)
+#define _KREF_H_
+
+#include <linux/types.h>
+#include <asm/atomic.h>
+
+
+struct kref {
+	atomic_t refcount;
+	void (*release)(struct kref *kref);
+};
+
+void kref_init(struct kref *kref, void (*release)(struct kref *));
+struct kref *kref_get(struct kref *kref);
+void kref_put(struct kref *kref);
+
+
+#endif /* _KREF_H_ */
diff -Nru a/include/linux/libata.h b/include/linux/libata.h
--- a/include/linux/libata.h	Sat Apr  3 19:38:40 2004
+++ b/include/linux/libata.h	Sat Apr  3 19:38:40 2004
@@ -28,7 +28,6 @@
 #include <asm/io.h>
 #include <linux/ata.h>
 
-
 /*
  * compile-time options
  */
@@ -82,7 +81,7 @@
 	ATA_SHT_EMULATED	= 1,
 	ATA_SHT_CMD_PER_LUN	= 1,
 	ATA_SHT_THIS_ID		= -1,
-	ATA_SHT_USE_CLUSTERING	= 1,
+	ATA_SHT_USE_CLUSTERING	= 0,
 
 	/* struct ata_device stuff */
 	ATA_DFLAG_LBA48		= (1 << 0), /* device supports LBA48 */
@@ -183,12 +182,15 @@
 	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;
@@ -248,7 +250,7 @@
 	struct ata_port		*ap;
 	struct ata_device	*dev;
 
-	struct scsi_cmnd		*scsicmd;
+	struct scsi_cmnd	*scsicmd;
 	void			(*scsidone)(struct scsi_cmnd *);
 
 	struct list_head	node;
@@ -360,7 +362,7 @@
 	u8   (*check_status)(struct ata_port *ap);
 
 	void (*phy_reset) (struct ata_port *ap);
-	void (*phy_config) (struct ata_port *ap);
+	void (*post_set_mode) (struct ata_port *ap);
 
 	void (*bmdma_start) (struct ata_queued_cmd *qc);
 	void (*fill_sg) (struct ata_queued_cmd *qc);
@@ -394,7 +396,6 @@
 };
 
 extern void ata_port_probe(struct ata_port *);
-extern void pata_phy_config(struct ata_port *ap);
 extern void sata_phy_reset(struct ata_port *ap);
 extern void ata_bus_reset(struct ata_port *ap);
 extern void ata_port_disable(struct ata_port *);
@@ -408,6 +409,7 @@
 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 +467,8 @@
 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 +496,7 @@
 	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 -Nru a/include/linux/lockd/debug.h b/include/linux/lockd/debug.h
--- a/include/linux/lockd/debug.h	Sat Apr  3 19:38:55 2004
+++ b/include/linux/lockd/debug.h	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
--- a/include/linux/lockd/lockd.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/lockd/lockd.h	Sat Apr  3 19:38:41 2004
@@ -165,6 +165,7 @@
 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 -Nru a/include/linux/loop.h b/include/linux/loop.h
--- a/include/linux/loop.h	Sat Apr  3 19:38:56 2004
+++ b/include/linux/loop.h	Sat Apr  3 19:38:56 2004
@@ -153,5 +153,6 @@
 #define LOOP_GET_STATUS		0x4C03
 #define LOOP_SET_STATUS64	0x4C04
 #define LOOP_GET_STATUS64	0x4C05
+#define LOOP_CHANGE_FD		0x4C06
 
 #endif
diff -Nru a/include/linux/major.h b/include/linux/major.h
--- a/include/linux/major.h	Sat Apr  3 19:38:42 2004
+++ b/include/linux/major.h	Sat Apr  3 19:38:42 2004
@@ -163,4 +163,6 @@
 #define IBM_TTY3270_MAJOR	227
 #define IBM_FS3270_MAJOR	228
 
+#define VIOTAPE_MAJOR		230
+
 #endif
diff -Nru a/include/linux/miscdevice.h b/include/linux/miscdevice.h
--- a/include/linux/miscdevice.h	Sat Apr  3 19:38:44 2004
+++ b/include/linux/miscdevice.h	Sat Apr  3 19:38:44 2004
@@ -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
@@ -20,6 +19,7 @@
 #define SUN_OPENPROM_MINOR 139
 #define DMAPI_MINOR		140	/* DMAPI */
 #define NVRAM_MINOR 144
+#define STORE_QUEUE_MINOR	155
 #define I2O_MINOR 166
 #define MICROCODE_MINOR		184
 #define MWAVE_MINOR	219		/* ACP/Mwave Modem */
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/mm.h	Sat Apr  3 19:38:41 2004
@@ -112,6 +112,9 @@
 #define VM_HUGETLB	0x00400000	/* Huge TLB Page VM */
 #define VM_NONLINEAR	0x00800000	/* Is non-linear (remap_file_pages) */
 
+/* It makes sense to apply VM_ACCOUNT to this vma. */
+#define VM_MAYACCT(vma) (!!((vma)->vm_flags & VM_HUGETLB))
+
 #ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
 #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
 #endif
@@ -152,6 +155,12 @@
 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,7 +177,7 @@
  * 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. */
@@ -333,7 +342,7 @@
  * 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)
diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h	Sat Apr  3 19:38:44 2004
+++ b/include/linux/mmzone.h	Sat Apr  3 19:38:44 2004
@@ -76,7 +76,8 @@
 	spinlock_t		lru_lock;	
 	struct list_head	active_list;
 	struct list_head	inactive_list;
-	atomic_t		refill_counter;
+	atomic_t		nr_scan_active;
+	atomic_t		nr_scan_inactive;
 	unsigned long		nr_active;
 	unsigned long		nr_inactive;
 	int			all_unreclaimable; /* All pages pinned */
@@ -213,6 +214,7 @@
 	int node_id;
 	struct pglist_data *pgdat_next;
 	wait_queue_head_t       kswapd_wait;
+	struct task_struct *kswapd;
 } pg_data_t;
 
 #define node_present_pages(nid)	(NODE_DATA(nid)->node_present_pages)
@@ -288,11 +290,16 @@
 	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;
 int min_free_kbytes_sysctl_handler(struct ctl_table *, int, struct file *, 
-					  void *, size_t *);
+					  void __user *, size_t *);
 
 #include <linux/topology.h>
 /* Returns the number of the current Node. */
@@ -310,7 +317,7 @@
 
 #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 -Nru a/include/linux/moduleparam.h b/include/linux/moduleparam.h
--- a/include/linux/moduleparam.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/moduleparam.h	Sat Apr  3 19:38:43 2004
@@ -126,12 +126,15 @@
 #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 -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h	Sat Apr  3 19:38:55 2004
+++ b/include/linux/netdevice.h	Sat Apr  3 19:38:55 2004
@@ -29,11 +29,11 @@
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
 
+#ifdef __KERNEL__
 #include <asm/atomic.h>
 #include <asm/cache.h>
 #include <asm/byteorder.h>
 
-#ifdef __KERNEL__
 #include <linux/config.h>
 #include <linux/device.h>
 #include <linux/percpu.h>
@@ -456,6 +456,12 @@
 						     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 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_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);
 }
 
@@ -773,6 +790,17 @@
 #define netif_msg_pktdata(p)	((p)->msg_enable & NETIF_MSG_PKTDATA)
 #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? */
 
diff -Nru a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
--- a/include/linux/netfilter_ipv4/ip_conntrack.h	Sat Apr  3 19:38:55 2004
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h	Sat Apr  3 19:38:55 2004
@@ -156,7 +156,8 @@
 	union ip_conntrack_expect_help help;
 };
 
-#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+struct ip_conntrack_helper;
+
 struct ip_conntrack
 {
 	/* Usage count in here is 1 for hash table/destruct timer, 1 per skb,
diff -Nru a/include/linux/netpoll.h b/include/linux/netpoll.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/netpoll.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,37 @@
+/*
+ * 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/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 -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h	Sat Apr  3 19:38:42 2004
+++ b/include/linux/nfs_fs.h	Sat Apr  3 19:38:42 2004
@@ -99,7 +99,7 @@
 	/*
 	 * Various flags
 	 */
-	unsigned short		flags;
+	unsigned int		flags;
 
 	/*
 	 * read_cache_jiffies is when we started read-caching this inode,
@@ -118,19 +118,22 @@
 	 *
 	 *	mtime != read_cache_mtime
 	 */
+	unsigned long		readdir_timestamp;
 	unsigned long		read_cache_jiffies;
-	struct timespec		read_cache_ctime;
-	struct timespec		read_cache_mtime;
-	__u64			read_cache_isize;
 	unsigned long		attrtimeo;
 	unsigned long		attrtimeo_timestamp;
 	__u64			change_attr;		/* v4 only */
 
+	/* "Generation counter" for the attribute cache. This is
+	 * bumped whenever we update the metadata on the
+	 * server.
+	 */
+	unsigned long		cache_change_attribute;
 	/*
-	 * Timestamp that dates the change made to read_cache_mtime.
-	 * This is of use for dentry revalidation
+	 * Counter indicating the number of outstanding requests that
+	 * will cause a file data update.
 	 */
-	unsigned long		cache_mtime_jiffies;
+	atomic_t		data_updates;
 
 	struct nfs_access_cache	cache_access;
 
@@ -170,8 +173,9 @@
 #define NFS_INO_STALE		0x0001		/* possible stale inode */
 #define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
 #define NFS_INO_REVALIDATING	0x0004		/* revalidating attrs */
-#define NFS_INO_FLUSH		0x0008		/* inode is due for flushing */
-#define NFS_INO_FAKE_ROOT	0x0080		/* root inode placeholder */
+#define NFS_INO_INVALID_ATTR	0x0008		/* cached attrs are invalid */
+#define NFS_INO_INVALID_DATA	0x0010		/* cached data is invalid */
+#define NFS_INO_INVALID_ATIME	0x0020		/* cached atime is invalid */
 
 static inline struct nfs_inode *NFS_I(struct inode *inode)
 {
@@ -186,15 +190,7 @@
 #define NFS_ADDR(inode)			(RPC_PEERADDR(NFS_CLIENT(inode)))
 #define NFS_COOKIEVERF(inode)		(NFS_I(inode)->cookieverf)
 #define NFS_READTIME(inode)		(NFS_I(inode)->read_cache_jiffies)
-#define NFS_MTIME_UPDATE(inode)		(NFS_I(inode)->cache_mtime_jiffies)
-#define NFS_CACHE_CTIME(inode)		(NFS_I(inode)->read_cache_ctime)
-#define NFS_CACHE_MTIME(inode)		(NFS_I(inode)->read_cache_mtime)
-#define NFS_CACHE_ISIZE(inode)		(NFS_I(inode)->read_cache_isize)
 #define NFS_CHANGE_ATTR(inode)		(NFS_I(inode)->change_attr)
-#define NFS_CACHEINV(inode) \
-do { \
-	NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
-} while (0)
 #define NFS_ATTRTIMEO(inode)		(NFS_I(inode)->attrtimeo)
 #define NFS_MINATTRTIMEO(inode) \
 	(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
@@ -207,10 +203,20 @@
 #define NFS_FLAGS(inode)		(NFS_I(inode)->flags)
 #define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
 #define NFS_STALE(inode)		(NFS_FLAGS(inode) & NFS_INO_STALE)
-#define NFS_FAKE_ROOT(inode)		(NFS_FLAGS(inode) & NFS_INO_FAKE_ROOT)
 
 #define NFS_FILEID(inode)		(NFS_I(inode)->fileid)
 
+static inline int nfs_caches_unstable(struct inode *inode)
+{
+	return atomic_read(&NFS_I(inode)->data_updates) != 0;
+}
+
+static inline void NFS_CACHEINV(struct inode *inode)
+{
+	if (!nfs_caches_unstable(inode))
+		NFS_FLAGS(inode) |= NFS_INO_INVALID_ATTR;
+}
+
 static inline int nfs_server_capable(struct inode *inode, int cap)
 {
 	return NFS_SERVER(inode)->caps & cap;
@@ -227,13 +233,37 @@
 	return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
 }
 
+/**
+ * nfs_save_change_attribute - Returns the inode attribute change cookie
+ * @inode - pointer to inode
+ * The "change attribute" is updated every time we finish an operation
+ * that will result in a metadata change on the server.
+ */
+static inline long nfs_save_change_attribute(struct inode *inode)
+{
+	return NFS_I(inode)->cache_change_attribute;
+}
+
+/**
+ * nfs_verify_change_attribute - Detects NFS inode cache updates
+ * @inode - pointer to inode
+ * @chattr - previously saved change attribute
+ * Return "false" if metadata has been updated (or is in the process of
+ * being updated) since the change attribute was saved.
+ */
+static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr)
+{
+	return !nfs_caches_unstable(inode)
+		&& chattr == NFS_I(inode)->cache_change_attribute;
+}
+
 /*
  * linux/fs/nfs/inode.c
  */
 extern void nfs_zap_caches(struct inode *);
 extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
 				struct nfs_fattr *);
-extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *);
+extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
 extern int nfs_permission(struct inode *, int, struct nameidata *);
 extern void nfs_set_mmcred(struct inode *, struct rpc_cred *);
@@ -241,6 +271,13 @@
 extern int nfs_release(struct inode *, struct file *);
 extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int nfs_setattr(struct dentry *, struct iattr *);
+extern void nfs_begin_attr_update(struct inode *);
+extern void nfs_end_attr_update(struct inode *);
+extern void nfs_begin_data_update(struct inode *);
+extern void nfs_end_data_update(struct inode *);
+
+/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
+extern u32 root_nfs_parse_addr(char *name); /*__init*/
 
 /*
  * linux/fs/nfs/file.c
@@ -309,16 +346,15 @@
  * Try to write back everything synchronously (but check the
  * return value!)
  */
-extern int  nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int);
-extern int  nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_sync_inode(struct inode *, unsigned long, unsigned int, int);
+extern int  nfs_flush_inode(struct inode *, unsigned long, unsigned int, int);
 extern int  nfs_flush_list(struct list_head *, int, int);
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-extern int  nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_commit_inode(struct inode *, unsigned long, unsigned int, int);
 extern int  nfs_commit_list(struct list_head *, int);
 #else
 static inline int
-nfs_commit_file(struct inode *inode, struct file *file, unsigned long offset,
-		unsigned int len, int flags)
+nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how)
 {
 	return 0;
 }
@@ -333,7 +369,7 @@
 static inline int
 nfs_wb_all(struct inode *inode)
 {
-	int error = nfs_sync_file(inode, 0, 0, 0, FLUSH_WAIT);
+	int error = nfs_sync_inode(inode, 0, 0, FLUSH_WAIT);
 	return (error < 0) ? error : 0;
 }
 
@@ -343,21 +379,11 @@
 static inline int
 nfs_wb_page(struct inode *inode, struct page* page)
 {
-	int error = nfs_sync_file(inode, 0, page->index, 1,
+	int error = nfs_sync_inode(inode, page->index, 1,
 						FLUSH_WAIT | FLUSH_STABLE);
 	return (error < 0) ? error : 0;
 }
 
-/*
- * Write back all pending writes for one user.. 
- */
-static inline int
-nfs_wb_file(struct inode *inode, struct file *file)
-{
-	int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT);
-	return (error < 0) ? error : 0;
-}
-
 /* Hack for future NFS swap support */
 #ifndef IS_SWAPFILE
 # define IS_SWAPFILE(inode)	(0)
@@ -383,20 +409,27 @@
 /*
  * inline functions
  */
-static inline int
-nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
+
+static inline int nfs_attribute_timeout(struct inode *inode)
 {
-	if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
-		return NFS_STALE(inode) ? -ESTALE : 0;
-	return __nfs_revalidate_inode(server, inode);
+	struct nfs_inode *nfsi = NFS_I(inode);
+
+	return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
 }
 
-static inline int
-nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+/**
+ * nfs_revalidate_inode - Revalidate the inode attributes
+ * @server - pointer to nfs_server struct
+ * @inode - pointer to inode struct
+ *
+ * Updates inode attribute information by retrieving the data from the server.
+ */
+static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
-		return 0;
-	return __nfs_refresh_inode(inode,fattr);
+	if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
+			&& !nfs_attribute_timeout(inode))
+		return NFS_STALE(inode) ? -ESTALE : 0;
+	return __nfs_revalidate_inode(server, inode);
 }
 
 static inline loff_t
@@ -661,7 +694,7 @@
 #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 -Nru a/include/linux/nfs_page.h b/include/linux/nfs_page.h
--- a/include/linux/nfs_page.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/nfs_page.h	Sat Apr  3 19:38:41 2004
@@ -53,7 +53,7 @@
 extern	void nfs_list_add_request(struct nfs_page *, struct list_head *);
 
 extern	int nfs_scan_list(struct list_head *, struct list_head *,
-			  struct file *, unsigned long, unsigned int);
+			  unsigned long, unsigned int);
 extern	int nfs_coalesce_requests(struct list_head *, struct list_head *,
 				  unsigned int);
 extern  int nfs_wait_on_request(struct nfs_page *);
diff -Nru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
--- a/include/linux/nfs_xdr.h	Sat Apr  3 19:38:55 2004
+++ b/include/linux/nfs_xdr.h	Sat Apr  3 19:38:55 2004
@@ -700,7 +700,7 @@
 	struct inode_operations *dir_inode_ops;
 
 	int	(*getroot) (struct nfs_server *, struct nfs_fh *,
-			    struct nfs_fattr *);
+			    struct nfs_fsinfo *);
 	int	(*getattr) (struct inode *, struct nfs_fattr *);
 	int	(*setattr) (struct dentry *, struct nfs_fattr *,
 			    struct iattr *);
diff -Nru a/include/linux/notifier.h b/include/linux/notifier.h
--- a/include/linux/notifier.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/notifier.h	Sat Apr  3 19:38:41 2004
@@ -63,7 +63,6 @@
 #define CPU_ONLINE	0x0002 /* CPU (unsigned)v is up */
 #define CPU_UP_PREPARE	0x0003 /* CPU (unsigned)v coming up */
 #define CPU_UP_CANCELED	0x0004 /* CPU (unsigned)v NOT coming up */
-#define CPU_OFFLINE	0x0005 /* CPU (unsigned)v offline (still scheduling) */
 #define CPU_DEAD	0x0006 /* CPU (unsigned)v dead */
 
 #endif /* __KERNEL__ */
diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h
--- a/include/linux/page-flags.h	Sat Apr  3 19:38:54 2004
+++ b/include/linux/page-flags.h	Sat Apr  3 19:38:54 2004
@@ -98,23 +98,38 @@
 	unsigned long pgpgout;		/* Disk writes */
 	unsigned long pswpin;		/* swap reads */
 	unsigned long pswpout;		/* swap writes */
-	unsigned long pgalloc;		/* page allocations */
+	unsigned long pgalloc_high;	/* page allocations */
 
+	unsigned long pgalloc_normal;
+	unsigned long pgalloc_dma;
 	unsigned long pgfree;		/* page freeings */
 	unsigned long pgactivate;	/* pages moved inactive->active */
 	unsigned long pgdeactivate;	/* pages moved active->inactive */
+
 	unsigned long pgfault;		/* faults (major+minor) */
 	unsigned long pgmajfault;	/* faults (major only) */
-
-	unsigned long pgscan;		/* pages scanned by page reclaim */
-	unsigned long pgrefill;		/* inspected in refill_inactive_zone */
-	unsigned long pgsteal;		/* total pages reclaimed */
+	unsigned long pgrefill_high;	/* inspected in refill_inactive_zone */
+	unsigned long pgrefill_normal;
+	unsigned long pgrefill_dma;
+
+	unsigned long pgsteal_high;	/* total highmem pages reclaimed */
+	unsigned long pgsteal_normal;
+	unsigned long pgsteal_dma;
+	unsigned long pgscan_kswapd_high;/* total highmem pages scanned */
+	unsigned long pgscan_kswapd_normal;
+
+	unsigned long pgscan_kswapd_dma;
+	unsigned long pgscan_direct_high;/* total highmem pages scanned */
+	unsigned long pgscan_direct_normal;
+	unsigned long pgscan_direct_dma;
 	unsigned long pginodesteal;	/* pages reclaimed via inode freeing */
-	unsigned long kswapd_steal;	/* pages reclaimed by kswapd */
 
+	unsigned long slabs_scanned;	/* slab objects scanned */
+	unsigned long kswapd_steal;	/* pages reclaimed by kswapd */
 	unsigned long kswapd_inodesteal;/* reclaimed via kswapd inode freeing */
 	unsigned long pageoutrun;	/* kswapd's calls to page reclaim */
 	unsigned long allocstall;	/* direct reclaim calls */
+
 	unsigned long pgrotated;	/* pages rotated to tail of the LRU */
 } ____cacheline_aligned;
 
@@ -131,11 +146,24 @@
 		local_irq_restore(flags);				\
 	} while (0)
 
+
 #define inc_page_state(member)	mod_page_state(member, 1UL)
 #define dec_page_state(member)	mod_page_state(member, 0UL - 1)
 #define add_page_state(member,delta) mod_page_state(member, (delta))
 #define sub_page_state(member,delta) mod_page_state(member, 0UL - (delta))
 
+#define mod_page_state_zone(zone, member, delta)			\
+	do {								\
+		unsigned long flags;					\
+		local_irq_save(flags);					\
+		if (is_highmem(zone))					\
+			__get_cpu_var(page_states).member##_high += (delta);\
+		else if (is_normal(zone))				\
+			__get_cpu_var(page_states).member##_normal += (delta);\
+		else							\
+			__get_cpu_var(page_states).member##_dma += (delta);\
+		local_irq_restore(flags);				\
+	} while (0)
 
 /*
  * Manipulation of page state flags
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/pci.h	Sat Apr  3 19:38:43 2004
@@ -393,11 +393,6 @@
 					   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. */
@@ -723,6 +718,10 @@
 /* Include architecture-dependent settings and functions */
 
 #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
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/pci_ids.h	Sat Apr  3 19:38:43 2004
@@ -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
@@ -1631,8 +1634,9 @@
 #define PCI_SUBDEVICE_ID_CHASE_PCIRAS8		0xF010
 
 #define PCI_VENDOR_ID_AUREAL		0x12eb
-#define PCI_DEVICE_ID_AUREAL_VORTEX_1	0x0001
-#define PCI_DEVICE_ID_AUREAL_VORTEX_2	0x0002
+#define PCI_DEVICE_ID_AUREAL_VORTEX	0x0001
+#define PCI_DEVICE_ID_AUREAL_VORTEX2	0x0002
+#define PCI_DEVICE_ID_AUREAL_ADVANTAGE	0x0003
 
 #define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8
 #define PCI_DEVICE_ID_LML_33R10		0x8a02
@@ -1833,6 +1837,12 @@
 #define PCI_DEVICE_ID_TIGON3_5901	0x170d
 #define PCI_DEVICE_ID_TIGON3_5901_2	0x170e
 #define PCI_DEVICE_ID_BCM4401		0x4401
+
+#define PCI_VENDOR_ID_ENE		0x1524
+#define PCI_DEVICE_ID_ENE_1211		0x1211
+#define PCI_DEVICE_ID_ENE_1225		0x1225
+#define PCI_DEVICE_ID_ENE_1410		0x1410
+#define PCI_DEVICE_ID_ENE_1420		0x1420
 
 #define PCI_VENDOR_ID_SYBA		0x1592
 #define PCI_DEVICE_ID_SYBA_2P_EPP	0x0782
diff -Nru a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
--- a/include/linux/pkt_sched.h	Sat Apr  3 19:38:54 2004
+++ b/include/linux/pkt_sched.h	Sat Apr  3 19:38:54 2004
@@ -432,4 +432,10 @@
 
 #define TCA_ATM_MAX	TCA_ATM_STATE
 
+/* Delay section */
+struct tc_dly_qopt
+{
+	__u32	latency;
+	__u32   limit;
+};	
 #endif
diff -Nru a/include/linux/proc_fs.h b/include/linux/proc_fs.h
--- a/include/linux/proc_fs.h	Sat Apr  3 19:38:57 2004
+++ b/include/linux/proc_fs.h	Sat Apr  3 19:38:57 2004
@@ -141,10 +141,6 @@
 	return;
 }
 #endif /* CONFIG_PROC_DEVICETREE */
-/*
- * proc_rtas.c
- */
-extern void proc_rtas_init(void);
 
 extern struct proc_dir_entry *proc_symlink(const char *,
 		struct proc_dir_entry *, const char *);
diff -Nru a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
--- a/include/linux/raid/md_k.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/raid/md_k.h	Sat Apr  3 19:38:41 2004
@@ -212,9 +212,9 @@
 
 	struct mdk_thread_s		*thread;	/* management thread */
 	struct mdk_thread_s		*sync_thread;	/* doing resync or reconstruct */
-	unsigned long			curr_resync;	/* blocks scheduled */
+	sector_t			curr_resync;	/* blocks scheduled */
 	unsigned long			resync_mark;	/* a recent timestamp */
-	unsigned long			resync_mark_cnt;/* blocks written at resync_mark */
+	sector_t			resync_mark_cnt;/* blocks written at resync_mark */
 
 	/* recovery/resync flags 
 	 * NEEDED:   we might need to start a resync/recover
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Sat Apr  3 19:38:55 2004
+++ b/include/linux/reiserfs_fs.h	Sat Apr  3 19:38:55 2004
@@ -1335,7 +1335,8 @@
 #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);})
 
 
 /***************************************************************************/
@@ -1943,11 +1944,10 @@
 
 #define PROC_EXP( e )   e
 
-#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
 #define __PINFO( sb ) REISERFS_SB(sb) -> s_proc_info_data
 #define PROC_INFO_MAX( sb, field, value )								\
     __PINFO( sb ).field =												\
-        MAX( REISERFS_SB( sb ) -> s_proc_info_data.field, value )
+        max( REISERFS_SB( sb ) -> s_proc_info_data.field, value )
 #define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) )
 #define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) )
 #define PROC_INFO_BH_STAT( sb, bh, level )							\
diff -Nru a/include/linux/rmap-locking.h b/include/linux/rmap-locking.h
--- a/include/linux/rmap-locking.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/rmap-locking.h	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/sched.h	Sat Apr  3 19:38:41 2004
@@ -179,7 +179,9 @@
 struct namespace;
 
 /* Maximum number of active map areas.. This is a random (large) number */
-#define MAX_MAP_COUNT	(65536)
+#define DEFAULT_MAX_MAP_COUNT	65536
+
+extern int sysctl_max_map_count;
 
 #include <linux/aio.h>
 
@@ -547,6 +549,8 @@
 #define node_nr_running_init() {}
 #endif
 
+/* Move tasks off this (offline) CPU onto another. */
+extern void migrate_all_tasks(void);
 extern void set_user_nice(task_t *p, long nice);
 extern int task_prio(task_t *p);
 extern int task_nice(task_t *p);
@@ -560,13 +564,9 @@
  */
 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 -Nru a/include/linux/security.h b/include/linux/security.h
--- a/include/linux/security.h	Sat Apr  3 19:38:54 2004
+++ b/include/linux/security.h	Sat Apr  3 19:38:54 2004
@@ -177,7 +177,7 @@
  *	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 @@
 
 	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 @@
 	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 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 -Nru a/include/linux/serialP.h b/include/linux/serialP.h
--- a/include/linux/serialP.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/serialP.h	Sat Apr  3 19:38:41 2004
@@ -26,11 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/circ_buf.h>
 #include <linux/wait.h>
-#if (LINUX_VERSION_CODE < 0x020300)
-/* Unfortunate, but Linux 2.2 needs async_icount defined here and
- * it got moved in 2.3 */
-#include <linux/serial.h>
-#endif
 
 struct serial_state {
 	int	magic;
diff -Nru a/include/linux/serial_core.h b/include/linux/serial_core.h
--- a/include/linux/serial_core.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/serial_core.h	Sat Apr  3 19:38:41 2004
@@ -78,6 +78,11 @@
 #define PORT_MAC_ZILOG	50	/* m68k : not yet implemented */
 #define PORT_PMAC_ZILOG	51
 
+/* SH-SCI */
+#define PORT_SCI	52
+#define PORT_SCIF	53
+#define PORT_IRDA	54
+
 #ifdef __KERNEL__
 
 #include <linux/config.h>
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h	Sat Apr  3 19:38:44 2004
+++ b/include/linux/serio.h	Sat Apr  3 19:38:44 2004
@@ -117,6 +117,7 @@
 #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 @@
 #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 -Nru a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
--- a/include/linux/sunrpc/debug.h	Sat Apr  3 19:38:57 2004
+++ b/include/linux/sunrpc/debug.h	Sat Apr  3 19:38:57 2004
@@ -54,7 +54,7 @@
 
 #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 @@
 	CTL_NFSDEBUG,
 	CTL_NFSDDEBUG,
 	CTL_NLMDEBUG,
+	CTL_SLOTTABLE_UDP,
+	CTL_SLOTTABLE_TCP,
 };
 
 #endif /* _LINUX_SUNRPC_DEBUG_H_ */
diff -Nru a/include/linux/sunrpc/timer.h b/include/linux/sunrpc/timer.h
--- a/include/linux/sunrpc/timer.h	Sat Apr  3 19:38:44 2004
+++ b/include/linux/sunrpc/timer.h	Sat Apr  3 19:38:44 2004
@@ -25,9 +25,18 @@
 
 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 -Nru a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
--- a/include/linux/sunrpc/xdr.h	Sat Apr  3 19:38:56 2004
+++ b/include/linux/sunrpc/xdr.h	Sat Apr  3 19:38:56 2004
@@ -87,7 +87,7 @@
 /*
  * 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 -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h	Sat Apr  3 19:38:54 2004
+++ b/include/linux/sunrpc/xprt.h	Sat Apr  3 19:38:54 2004
@@ -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_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 xdr_buf		rq_private_buf;		/* The receive buffer
 							 * used in the softirq.
 							 */
-
 	/*
 	 * For authentication (e.g. auth_des)
 	 */
@@ -146,8 +146,9 @@
 	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 @@
 				stream     : 1;	/* TCP */
 
 	/*
+	 * XID
+	 */
+	__u32			xid;		/* Next XID value to use */
+
+	/*
 	 * State of TCP reply receive stuff
 	 */
 	u32			tcp_recm,	/* Fragment header */
@@ -163,6 +169,11 @@
 				tcp_offset;	/* fragment offset */
 	unsigned long		tcp_copied,	/* copied to request */
 				tcp_flags;
+	/*
+	 * Connection of sockets
+	 */
+	struct work_struct	sock_connect;
+	unsigned short		port;
 	/*
 	 * Disconnection of idle sockets
 	 */
diff -Nru a/include/linux/swapops.h b/include/linux/swapops.h
--- a/include/linux/swapops.h	Sat Apr  3 19:38:40 2004
+++ b/include/linux/swapops.h	Sat Apr  3 19:38:40 2004
@@ -15,11 +15,11 @@
 /*
  * Store a type+offset into a swp_entry_t in an arch-independent format
  */
-static inline swp_entry_t swp_entry(unsigned type, pgoff_t offset)
+static inline swp_entry_t swp_entry(unsigned long type, pgoff_t offset)
 {
 	swp_entry_t ret;
 
-	ret.val = ((unsigned long)type << SWP_TYPE_SHIFT(ret)) |
+	ret.val = (type << SWP_TYPE_SHIFT(ret)) |
 			(offset & SWP_OFFSET_MASK(ret));
 	return ret;
 }
diff -Nru a/include/linux/syscalls.h b/include/linux/syscalls.h
--- a/include/linux/syscalls.h	Sat Apr  3 19:38:57 2004
+++ b/include/linux/syscalls.h	Sat Apr  3 19:38:57 2004
@@ -60,8 +60,8 @@
 #include <asm/signal.h>
 #include <linux/quota.h>
 
-asmlinkage long sys_time(int *tloc);
-asmlinkage long sys_stime(time_t *tptr);
+asmlinkage long sys_time(int __user *tloc);
+asmlinkage long sys_stime(time_t __user *tptr);
 asmlinkage long sys_gettimeofday(struct timeval __user *tv,
 				struct timezone __user *tz);
 asmlinkage long sys_settimeofday(struct timeval __user *tv,
@@ -71,7 +71,7 @@
 asmlinkage long sys_times(struct tms __user *tbuf);
 
 asmlinkage long sys_gettid(void);
-asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp);
 asmlinkage unsigned long sys_alarm(unsigned int seconds);
 asmlinkage long sys_getpid(void);
 asmlinkage long sys_getppid(void);
@@ -79,8 +79,8 @@
 asmlinkage long sys_geteuid(void);
 asmlinkage long sys_getgid(void);
 asmlinkage long sys_getegid(void);
-asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
-asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
+asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid);
+asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid);
 asmlinkage long sys_getpgid(pid_t pid);
 asmlinkage long sys_getpgrp(void);
 asmlinkage long sys_getsid(pid_t pid);
@@ -98,7 +98,7 @@
 asmlinkage long sys_setsid(void);
 asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist);
 
-asmlinkage long sys_acct(const char *name);
+asmlinkage long sys_acct(const char __user *name);
 asmlinkage long sys_capget(cap_user_header_t header,
 				cap_user_data_t dataptr);
 asmlinkage long sys_capset(cap_user_header_t header,
@@ -157,8 +157,8 @@
 asmlinkage long sys_exit(int error_code);
 asmlinkage void sys_exit_group(int error_code);
 asmlinkage long sys_wait4(pid_t pid, unsigned int *stat_addr,
-				int options, struct rusage *ru);
-asmlinkage long sys_waitpid(pid_t pid, unsigned int *stat_addr, int options);
+				int options, struct rusage __user *ru);
+asmlinkage long sys_waitpid(pid_t pid, unsigned int __user *stat_addr, int options);
 asmlinkage long sys_set_tid_address(int __user *tidptr);
 asmlinkage long sys_futex(u32 __user *uaddr, int op, int val,
 			struct timespec __user *utime, u32 __user *uaddr2);
@@ -274,7 +274,7 @@
 				unsigned dev);
 asmlinkage long sys_link(const char __user *oldname,
 				const char __user *newname);
-asmlinkage long sys_symlink(const char *old, const char *new);
+asmlinkage long sys_symlink(const char __user *old, const char __user *new);
 asmlinkage long sys_unlink(const char __user *pathname);
 asmlinkage long sys_rename(const char __user *oldname,
 				const char __user *newname);
@@ -292,17 +292,17 @@
 asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd,
 				unsigned long arg);
 asmlinkage long sys_flock(unsigned int fd, unsigned int cmd);
-asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx);
+asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t __user *ctx);
 asmlinkage long sys_io_destroy(aio_context_t ctx);
 asmlinkage long sys_io_getevents(aio_context_t ctx_id,
 				long min_nr,
 				long nr,
-				struct io_event *events,
-				struct timespec *timeout);
+				struct io_event __user *events,
+				struct timespec __user *timeout);
 asmlinkage long sys_io_submit(aio_context_t, long,
-				struct iocb __user **);
-asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb *iocb,
-			      struct io_event *result);
+				struct iocb __user * __user *);
+asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb,
+			      struct io_event __user *result);
 asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd,
 				off_t __user *offset, size_t count);
 asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd,
@@ -321,9 +321,9 @@
 				uid_t user, gid_t group);
 asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group);
 #ifdef CONFIG_UID16
-asmlinkage long sys_chown16(const char *filename,
+asmlinkage long sys_chown16(const char __user *filename,
 				old_uid_t user, old_gid_t group);
-asmlinkage long sys_lchown16(const char *filename,
+asmlinkage long sys_lchown16(const char __user *filename,
 				old_uid_t user, old_gid_t group);
 asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group);
 asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid);
@@ -331,11 +331,11 @@
 asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid);
 asmlinkage long sys_setuid16(old_uid_t uid);
 asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid);
-asmlinkage long sys_getresuid16(old_uid_t *ruid,
-				old_uid_t *euid, old_uid_t *suid);
+asmlinkage long sys_getresuid16(old_uid_t __user *ruid,
+				old_uid_t __user *euid, old_uid_t __user *suid);
 asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid);
-asmlinkage long sys_getresgid16(old_gid_t *rgid,
-				old_gid_t *egid, old_gid_t *sgid);
+asmlinkage long sys_getresgid16(old_gid_t __user *rgid,
+				old_gid_t __user *egid, old_gid_t __user *sgid);
 asmlinkage long sys_setfsuid16(old_uid_t uid);
 asmlinkage long sys_setfsgid16(old_gid_t gid);
 asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist);
@@ -375,8 +375,8 @@
 asmlinkage long sys_chdir(const char __user *filename);
 asmlinkage long sys_fchdir(unsigned int fd);
 asmlinkage long sys_rmdir(const char __user *pathname);
-asmlinkage long sys_lookup_dcookie(u64 cookie64, char *buf, size_t len);
-asmlinkage long sys_quotactl(unsigned int cmd, const char *special,
+asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user *buf, size_t len);
+asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special,
 				qid_t id, caddr_t addr);
 asmlinkage long sys_getdents(unsigned int fd,
 				struct linux_dirent __user *dirent,
@@ -445,7 +445,7 @@
 				unsigned nsops,
 				const struct timespec __user *timeout);
 asmlinkage long sys_shmat(int shmid, char __user *shmaddr,
-				int shmflg, unsigned long *addr);
+				int shmflg, unsigned long __user *addr);
 asmlinkage long sys_shmget(key_t key, size_t size, int flag);
 asmlinkage long sys_shmdt(char __user *shmaddr);
 asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf);
@@ -453,10 +453,10 @@
 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,
-				void *buf);
+				void __user *buf);
 asmlinkage long sys_pciconfig_write(unsigned long bus, unsigned long dfn,
 				unsigned long off, unsigned long len,
-				void *buf);
+				void __user *buf);
 
 asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
 			unsigned long arg4, unsigned long arg5);
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/sysctl.h	Sat Apr  3 19:38:43 2004
@@ -158,6 +158,7 @@
 	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_MAX_MAP_COUNT=22,	/* int: Maximum number of mmaps/address-space */
 };
 
 
diff -Nru a/include/linux/tcp.h b/include/linux/tcp.h
--- a/include/linux/tcp.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/tcp.h	Sat Apr  3 19:38:43 2004
@@ -377,7 +377,6 @@
 
 /* TCP Westwood structure */
         struct {
-                __u32    bw_sample;        /* bandwidth sample */
                 __u32    bw_ns_est;        /* first bandwidth estimation..not too smoothed 8) */
                 __u32    bw_est;           /* bandwidth estimate */
                 __u32    rtt_win_sx;       /* here starts a new evaluation... */
diff -Nru a/include/linux/topology.h b/include/linux/topology.h
--- a/include/linux/topology.h	Sat Apr  3 19:38:45 2004
+++ b/include/linux/topology.h	Sat Apr  3 19:38:45 2004
@@ -54,4 +54,11 @@
 #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 -Nru a/include/linux/udf_fs.h b/include/linux/udf_fs.h
--- a/include/linux/udf_fs.h	Sat Apr  3 19:38:41 2004
+++ b/include/linux/udf_fs.h	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
--- a/include/linux/ufs_fs.h	Sat Apr  3 19:38:55 2004
+++ b/include/linux/ufs_fs.h	Sat Apr  3 19:38:55 2004
@@ -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 @@
 	__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 @@
 	__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 @@
 	__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 @@
 			__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 @@
 	} 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 @@
  * 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 @@
 	__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 @@
 	__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 @@
 	__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 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 -Nru a/include/linux/ufs_fs_i.h b/include/linux/ufs_fs_i.h
--- a/include/linux/ufs_fs_i.h	Sat Apr  3 19:38:44 2004
+++ b/include/linux/ufs_fs_i.h	Sat Apr  3 19:38:44 2004
@@ -17,6 +17,7 @@
 	union {
 		__u32	i_data[15];
 		__u8	i_symlink[4*15];
+		__u64	u2_i_data[15];
 	} i_u1;
 	__u32	i_flags;
 	__u32	i_gen;
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/usb.h	Sat Apr  3 19:38:43 2004
@@ -72,14 +72,11 @@
 
 /**
  * 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 @@
  *	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 @@
  * 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 @@
 /* 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 @@
 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 @@
  * @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 @@
  * @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 @@
  * 	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 @@
  *	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 @@
  * 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 @@
  * 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 @@
 	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 *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 -Nru a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
--- a/include/linux/usb_gadget.h	Sat Apr  3 19:38:43 2004
+++ b/include/linux/usb_gadget.h	Sat Apr  3 19:38:43 2004
@@ -117,7 +117,7 @@
 	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 @@
  * 	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_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 @@
 /**
  * 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 @@
 /* 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 -Nru a/include/net/flow.h b/include/net/flow.h
--- a/include/net/flow.h	Sat Apr  3 19:38:55 2004
+++ b/include/net/flow.h	Sat Apr  3 19:38:55 2004
@@ -77,7 +77,7 @@
 #define fl_icmp_type	uli_u.icmpt.type
 #define fl_icmp_code	uli_u.icmpt.code
 #define fl_ipsec_spi	uli_u.spi
-};
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
 
 #define FLOW_DIR_IN	0
 #define FLOW_DIR_OUT	1
diff -Nru a/include/net/irda/vlsi_ir.h b/include/net/irda/vlsi_ir.h
--- a/include/net/irda/vlsi_ir.h	Sat Apr  3 19:38:44 2004
+++ b/include/net/irda/vlsi_ir.h	Sat Apr  3 19:38:44 2004
@@ -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 -Nru a/include/net/scm.h b/include/net/scm.h
--- a/include/net/scm.h	Sat Apr  3 19:38:43 2004
+++ b/include/net/scm.h	Sat Apr  3 19:38:43 2004
@@ -2,6 +2,7 @@
 #define __LINUX_NET_SCM_H
 
 #include <linux/limits.h>
+#include <linux/net.h>
 
 /* Well, we should have at least one descriptor open
  * to accept passed FDs 8)
diff -Nru a/include/net/xfrm.h b/include/net/xfrm.h
--- a/include/net/xfrm.h	Sat Apr  3 19:38:55 2004
+++ b/include/net/xfrm.h	Sat Apr  3 19:38:55 2004
@@ -166,7 +166,7 @@
 	struct dst_ops		*dst_ops;
 	void			(*garbage_collect)(void);
 	int			(*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
-	struct dst_entry	*(*find_bundle)(struct flowi *fl, struct rtable *rt, struct xfrm_policy *policy);
+	struct dst_entry	*(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy);
 	int			(*bundle_create)(struct xfrm_policy *policy, 
 						 struct xfrm_state **xfrm, 
 						 int nx,
diff -Nru a/include/pcmcia/cs.h b/include/pcmcia/cs.h
--- a/include/pcmcia/cs.h	Sat Apr  3 19:38:40 2004
+++ b/include/pcmcia/cs.h	Sat Apr  3 19:38:40 2004
@@ -422,8 +422,6 @@
 };
 
 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_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 -Nru a/include/scsi/scsi.h b/include/scsi/scsi.h
--- a/include/scsi/scsi.h	Sat Apr  3 19:38:56 2004
+++ b/include/scsi/scsi.h	Sat Apr  3 19:38:56 2004
@@ -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 @@
 #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 @@
 #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 -Nru a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
--- a/include/scsi/scsi_device.h	Sat Apr  3 19:38:41 2004
+++ b/include/scsi/scsi_device.h	Sat Apr  3 19:38:41 2004
@@ -15,7 +15,7 @@
  * 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 @@
 				 * 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 @@
 	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 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_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 -Nru a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
--- a/include/scsi/scsi_host.h	Sat Apr  3 19:38:41 2004
+++ b/include/scsi/scsi_host.h	Sat Apr  3 19:38:41 2004
@@ -11,6 +11,7 @@
 struct scsi_device;
 struct Scsi_Host;
 struct scsi_host_cmd_pool;
+struct scsi_transport_template;
 
 
 /*
@@ -395,6 +396,7 @@
 	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 -Nru a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/scsi/scsi_transport.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/scsi/scsi_transport_fc.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/scsi/scsi_transport_spi.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h
--- a/include/sound/ac97_codec.h	Sat Apr  3 19:38:43 2004
+++ b/include/sound/ac97_codec.h	Sat Apr  3 19:38:43 2004
@@ -226,10 +226,14 @@
 #define AC97_GPIO_LINE2_HL1R    0x8000  /* Opt./ Handset to Line2 relay control (out) */
 
 /* specific - SigmaTel */
+#define AC97_SIGMATEL_OUTSEL	0x64	/* Output Select, STAC9758 */
+#define AC97_SIGMATEL_INSEL	0x66	/* Input Select, STAC9758 */
+#define AC97_SIGMATEL_IOMISC	0x68	/* STAC9758 */
 #define AC97_SIGMATEL_ANALOG	0x6c	/* Analog Special */
 #define AC97_SIGMATEL_DAC2INVERT 0x6e
 #define AC97_SIGMATEL_BIAS1	0x70
 #define AC97_SIGMATEL_BIAS2	0x72
+#define AC97_SIGMATEL_VARIOUS	0x72	/* STAC9758 */
 #define AC97_SIGMATEL_MULTICHN	0x74	/* Multi-Channel programming */
 #define AC97_SIGMATEL_CIC1	0x76
 #define AC97_SIGMATEL_CIC2	0x78
@@ -456,7 +460,7 @@
 }
 static inline int ac97_is_rev22(ac97_t * ac97)
 {
-	return (ac97->ext_id & AC97_EI_REV_MASK) == AC97_EI_REV_22;
+	return (ac97->ext_id & AC97_EI_REV_MASK) >= AC97_EI_REV_22;
 }
 static inline int ac97_can_amap(ac97_t * ac97)
 {
@@ -484,7 +488,8 @@
 	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 -Nru a/include/sound/ak4117.h b/include/sound/ak4117.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/sound/ak4117.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/include/sound/asequencer.h b/include/sound/asequencer.h
--- a/include/sound/asequencer.h	Sat Apr  3 19:38:44 2004
+++ b/include/sound/asequencer.h	Sat Apr  3 19:38:44 2004
@@ -594,6 +594,7 @@
 #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 @@
 /* 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 -Nru a/include/sound/asound.h b/include/sound/asound.h
--- a/include/sound/asound.h	Sat Apr  3 19:38:45 2004
+++ b/include/sound/asound.h	Sat Apr  3 19:38:45 2004
@@ -153,7 +153,7 @@
  *                                                                           *
  *****************************************************************************/
 
-#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 -Nru a/include/sound/cs46xx.h b/include/sound/cs46xx.h
--- a/include/sound/cs46xx.h	Sat Apr  3 19:38:42 2004
+++ b/include/sound/cs46xx.h	Sat Apr  3 19:38:42 2004
@@ -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 @@
 	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 */
@@ -1726,6 +1722,8 @@
 	spinlock_t reg_lock;
 	unsigned int midcr;
 	unsigned int uartm;
+
+	struct snd_dma_device dma_dev;
 
 	int amplifier;
 	void (*amplifier_ctrl)(cs46xx_t *, int);
diff -Nru a/include/sound/cs8427.h b/include/sound/cs8427.h
--- a/include/sound/cs8427.h	Sat Apr  3 19:38:44 2004
+++ b/include/sound/cs8427.h	Sat Apr  3 19:38:44 2004
@@ -187,7 +187,8 @@
 #define CS8427_VER8427A		0x71
 
 int snd_cs8427_detect(snd_i2c_bus_t *bus, unsigned char addr);
-int snd_cs8427_create(snd_i2c_bus_t *bus, unsigned char addr, snd_i2c_device_t **r_cs8427);
+int snd_cs8427_create(snd_i2c_bus_t *bus, unsigned char addr,
+		      unsigned int reset_timeout, snd_i2c_device_t **r_cs8427);
 void snd_cs8427_reset(snd_i2c_device_t *cs8427);
 int snd_cs8427_reg_write(snd_i2c_device_t *device, unsigned char reg, unsigned char val);
 int snd_cs8427_reg_read(snd_i2c_device_t *device, unsigned char reg);
diff -Nru a/include/sound/emu10k1.h b/include/sound/emu10k1.h
--- a/include/sound/emu10k1.h	Sat Apr  3 19:38:42 2004
+++ b/include/sound/emu10k1.h	Sat Apr  3 19:38:42 2004
@@ -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 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 @@
 	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 @@
 	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 -Nru a/include/sound/info.h b/include/sound/info.h
--- a/include/sound/info.h	Sat Apr  3 19:38:54 2004
+++ b/include/sound/info.h	Sat Apr  3 19:38:54 2004
@@ -171,7 +171,7 @@
 					 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 -Nru a/include/sound/memalloc.h b/include/sound/memalloc.h
--- a/include/sound/memalloc.h	Sat Apr  3 19:38:41 2004
+++ b/include/sound/memalloc.h	Sat Apr  3 19:38:41 2004
@@ -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 @@
 	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 @@
 	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 @@
 {
 	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 -Nru a/include/sound/pcm.h b/include/sound/pcm.h
--- a/include/sound/pcm.h	Sat Apr  3 19:38:43 2004
+++ b/include/sound/pcm.h	Sat Apr  3 19:38:43 2004
@@ -428,7 +428,7 @@
 	snd_info_entry_t *proc_root;
 	snd_info_entry_t *proc_info_entry;
 #ifdef CONFIG_SND_DEBUG
-	unsigned int xrun_debug: 1;
+	unsigned int xrun_debug;	/* 0 = disabled, 1 = verbose, 2 = stacktrace */
 	snd_info_entry_t *proc_xrun_debug_entry;
 #endif
 };
@@ -889,6 +889,9 @@
 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 @@
 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 -Nru a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
--- a/include/sound/pcm_oss.h	Sat Apr  3 19:38:54 2004
+++ b/include/sound/pcm_oss.h	Sat Apr  3 19:38:54 2004
@@ -50,6 +50,7 @@
 	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 -Nru a/include/sound/sndmagic.h b/include/sound/sndmagic.h
--- a/include/sound/sndmagic.h	Sat Apr  3 19:38:42 2004
+++ b/include/sound/sndmagic.h	Sat Apr  3 19:38:42 2004
@@ -200,6 +200,9 @@
 #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 -Nru a/include/sound/trident.h b/include/sound/trident.h
--- a/include/sound/trident.h	Sat Apr  3 19:38:44 2004
+++ b/include/sound/trident.h	Sat Apr  3 19:38:44 2004
@@ -308,11 +308,9 @@
 	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 {
@@ -434,6 +432,8 @@
 
 	spinlock_t event_lock;
 	spinlock_t voice_alloc;
+
+	struct snd_dma_device dma_dev;
 
 	struct pci_dev *pci;
 	snd_card_t *card;
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Sat Apr  3 19:38:42 2004
+++ b/include/sound/version.h	Sat Apr  3 19:38:42 2004
@@ -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.4rc2"
+#define CONFIG_SND_DATE " (Tue Mar 30 08:19:30 2004 UTC)"
diff -Nru a/include/sound/ymfpci.h b/include/sound/ymfpci.h
--- a/include/sound/ymfpci.h	Sat Apr  3 19:38:42 2004
+++ b/include/sound/ymfpci.h	Sat Apr  3 19:38:42 2004
@@ -316,9 +316,8 @@
 	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 @@
 	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 -Nru a/init/do_mounts.c b/init/do_mounts.c
--- a/init/do_mounts.c	Sat Apr  3 19:38:42 2004
+++ b/init/do_mounts.c	Sat Apr  3 19:38:42 2004
@@ -66,11 +66,11 @@
 	/* 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 @@
 
 	/* 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';
@@ -163,6 +163,9 @@
 	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 +288,7 @@
 				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 +327,21 @@
 	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 -Nru a/init/do_mounts.h b/init/do_mounts.h
--- a/init/do_mounts.h	Sat Apr  3 19:38:45 2004
+++ b/init/do_mounts.h	Sat Apr  3 19:38:45 2004
@@ -1,4 +1,3 @@
-#define __KERNEL_SYSCALLS__
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/devfs_fs_kernel.h>
diff -Nru a/init/do_mounts_devfs.c b/init/do_mounts_devfs.c
--- a/init/do_mounts_devfs.c	Sat Apr  3 19:38:54 2004
+++ b/init/do_mounts_devfs.c	Sat Apr  3 19:38:54 2004
@@ -24,7 +24,7 @@
 {
 	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 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 @@
 			break;
 		n = do_read_dir(fd, p, size);
 		if (n > 0) {
-			close(fd);
+			sys_close(fd);
 			*len = n;
 			return p;
 		}
@@ -68,7 +68,7 @@
 		if (n < 0)
 			break;
 	}
-	close(fd);
+	sys_close(fd);
 	return NULL;
 }
 
diff -Nru a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
--- a/init/do_mounts_initrd.c	Sat Apr  3 19:38:41 2004
+++ b/init/do_mounts_initrd.c	Sat Apr  3 19:38:41 2004
@@ -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 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 @@
 	/* 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 @@
 
 	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 @@
 	/* 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 @@
 	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 @@
 			error = fd;
 		} else {
 			error = sys_ioctl(fd, BLKFLSBUF, 0);
-			close(fd);
+			sys_close(fd);
 		}
 		printk(!error ? "okay\n" : "failed\n");
 	}
diff -Nru a/init/do_mounts_md.c b/init/do_mounts_md.c
--- a/init/do_mounts_md.c	Sat Apr  3 19:38:55 2004
+++ b/init/do_mounts_md.c	Sat Apr  3 19:38:55 2004
@@ -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 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 @@
 				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 @@
 		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 @@
 			}
 
 			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 @@
 
 			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 @@
 			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 @@
 
 		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 @@
 	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 -Nru a/init/do_mounts_rd.c b/init/do_mounts_rd.c
--- a/init/do_mounts_rd.c	Sat Apr  3 19:38:54 2004
+++ b/init/do_mounts_rd.c	Sat Apr  3 19:38:54 2004
@@ -69,8 +69,8 @@
 	/*
 	 * 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 @@
 	/*
 	 * 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 @@
 	       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 @@
 	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 @@
 		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 @@
 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 @@
 {
 	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 @@
     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 -Nru a/init/initramfs.c b/init/initramfs.c
--- a/init/initramfs.c	Sat Apr  3 19:38:41 2004
+++ b/init/initramfs.c	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Sat Apr  3 19:38:41 2004
+++ b/init/main.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 	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++;
@@ -406,6 +409,7 @@
  * enable them
  */
 	lock_kernel();
+	page_address_init();
 	printk(linux_banner);
 	setup_arch(&command_line);
 	setup_per_cpu_areas();
@@ -449,7 +453,6 @@
 		initrd_start = 0;
 	}
 #endif
-	page_address_init();
 	mem_init();
 	kmem_cache_init();
 	if (late_time_init)
@@ -612,11 +615,11 @@
 	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 -Nru a/ipc/Makefile b/ipc/Makefile
--- a/ipc/Makefile	Sat Apr  3 19:38:41 2004
+++ b/ipc/Makefile	Sat Apr  3 19:38:41 2004
@@ -4,4 +4,5 @@
 
 obj-y   := util.o
 
+obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
 obj-$(CONFIG_SYSVIPC) += msg.o sem.o shm.o
diff -Nru a/ipc/compat.c b/ipc/compat.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/ipc/compat.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c	Sat Apr  3 19:38:42 2004
+++ b/ipc/sem.c	Sat Apr  3 19:38:42 2004
@@ -972,8 +972,10 @@
 	if(sma==NULL)
 		goto out;
 	un = ERR_PTR(-EIDRM);
-	if (sem_checkid(sma,semid))
-		goto out_unlock;
+	if (sem_checkid(sma,semid)) {
+		sem_unlock(sma);
+		goto out;
+	}
 	nsems = sma->sem_nsems;
 	sem_unlock(sma);
 
@@ -993,7 +995,6 @@
 	}
 	error = sem_revalidate(semid, sma, nsems, 0);
 	if (error) {
-		sem_unlock(sma);
 		unlock_semundo();
 		kfree(new);
 		un = ERR_PTR(error);
@@ -1005,7 +1006,6 @@
 	sma->undo = new;
 	sem_unlock(sma);
 	un = new;
-out_unlock:
 	unlock_semundo();
 out:
 	return un;
diff -Nru a/ipc/shm.c b/ipc/shm.c
--- a/ipc/shm.c	Sat Apr  3 19:38:43 2004
+++ b/ipc/shm.c	Sat Apr  3 19:38:43 2004
@@ -149,7 +149,7 @@
 
 static int shm_mmap(struct file * file, struct vm_area_struct * vma)
 {
-	update_atime(file->f_dentry->d_inode);
+	file_accessed(file);
 	vma->vm_ops = &shm_vm_ops;
 	shm_inc(file->f_dentry->d_inode->i_ino);
 	return 0;
@@ -656,7 +656,10 @@
 			if (shmflg & SHM_RND)
 				addr &= ~(SHMLBA-1);	   /* round down */
 			else
-				return -EINVAL;
+#ifndef __ARCH_FORCE_SHMLBA
+				if (addr & ~PAGE_MASK)
+#endif
+					return -EINVAL;
 		}
 		flags = MAP_SHARED | MAP_FIXED;
 	} else {
@@ -759,6 +762,21 @@
 
 	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
diff -Nru a/kernel/acct.c b/kernel/acct.c
--- a/kernel/acct.c	Sat Apr  3 19:38:43 2004
+++ b/kernel/acct.c	Sat Apr  3 19:38:43 2004
@@ -52,6 +52,7 @@
 #include <linux/security.h>
 #include <linux/vfs.h>
 #include <linux/jiffies.h>
+#include <linux/times.h>
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 #include <linux/blkdev.h> /* sector_div */
@@ -336,13 +337,13 @@
 
 	strlcpy(ac.ac_comm, current->comm, sizeof(ac.ac_comm));
 
-	elapsed = get_jiffies_64() - current->start_time;
+	elapsed = jiffies_64_to_clock_t(get_jiffies_64() - current->start_time);
 	ac.ac_etime = encode_comp_t(elapsed < (unsigned long) -1l ?
 	                       (unsigned long) elapsed : (unsigned long) -1l);
-	do_div(elapsed, HZ);
+	do_div(elapsed, USER_HZ);
 	ac.ac_btime = xtime.tv_sec - elapsed;
-	ac.ac_utime = encode_comp_t(current->utime);
-	ac.ac_stime = encode_comp_t(current->stime);
+	ac.ac_utime = encode_comp_t(jiffies_to_clock_t(current->utime));
+	ac.ac_stime = encode_comp_t(jiffies_to_clock_t(current->stime));
 	/* we really need to bite the bullet and change layout */
 	ac.ac_uid = current->uid;
 	ac.ac_gid = current->gid;
diff -Nru a/kernel/cpu.c b/kernel/cpu.c
--- a/kernel/cpu.c	Sat Apr  3 19:38:55 2004
+++ b/kernel/cpu.c	Sat Apr  3 19:38:55 2004
@@ -1,5 +1,6 @@
 /* CPU control.
- * (C) 2001 Rusty Russell
+ * (C) 2001, 2002, 2003, 2004 Rusty Russell
+ *
  * This code is licenced under the GPL.
  */
 #include <linux/proc_fs.h>
@@ -9,6 +10,10 @@
 #include <linux/sched.h>
 #include <linux/unistd.h>
 #include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/kmod.h>		/* for hotplug_path */
+#include <linux/kthread.h>
+#include <linux/stop_machine.h>
 #include <asm/semaphore.h>
 
 /* This protects CPUs going up and down... */
@@ -19,13 +24,142 @@
 /* Need to know about CPUs going up/down? */
 int register_cpu_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_register(&cpu_chain, nb);
+	int ret;
+
+	if ((ret = down_interruptible(&cpucontrol)) != 0)
+		return ret;
+	ret = notifier_chain_register(&cpu_chain, nb);
+	up(&cpucontrol);
+	return ret;
 }
+EXPORT_SYMBOL(register_cpu_notifier);
 
 void unregister_cpu_notifier(struct notifier_block *nb)
 {
-	notifier_chain_unregister(&cpu_chain,nb);
+	down(&cpucontrol);
+	notifier_chain_unregister(&cpu_chain, nb);
+	up(&cpucontrol);
+}
+EXPORT_SYMBOL(unregister_cpu_notifier);
+
+#ifdef CONFIG_HOTPLUG_CPU
+static inline void check_for_tasks(int cpu, struct task_struct *k)
+{
+	struct task_struct *p;
+
+	write_lock_irq(&tasklist_lock);
+	for_each_process(p) {
+		if (task_cpu(p) == cpu && p != k)
+			printk(KERN_WARNING "Task %s is on cpu %d\n",
+				p->comm, cpu);
+	}
+	write_unlock_irq(&tasklist_lock);
+}
+
+/* Notify userspace when a cpu event occurs, by running '/sbin/hotplug
+ * cpu' with certain environment variables set.  */
+static int cpu_run_sbin_hotplug(unsigned int cpu, const char *action)
+{
+	char *argv[3], *envp[5], cpu_str[12], action_str[32];
+	int i;
+
+	sprintf(cpu_str, "CPU=%d", cpu);
+	sprintf(action_str, "ACTION=%s", action);
+	/* FIXME: Add DEVPATH. --RR */
+
+	i = 0;
+	argv[i++] = hotplug_path;
+	argv[i++] = "cpu";
+	argv[i] = NULL;
+
+	i = 0;
+	/* minimal command environment */
+	envp[i++] = "HOME=/";
+	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp[i++] = cpu_str;
+	envp[i++] = action_str;
+	envp[i] = NULL;
+
+	return call_usermodehelper(argv[0], argv, envp, 0);
+}
+
+/* Take this CPU down. */
+static int take_cpu_down(void *unused)
+{
+	int err;
+
+	/* Take offline: makes arch_cpu_down somewhat easier. */
+	cpu_clear(smp_processor_id(), cpu_online_map);
+
+	/* Ensure this CPU doesn't handle any more interrupts. */
+	err = __cpu_disable();
+	if (err < 0)
+		cpu_set(smp_processor_id(), cpu_online_map);
+	else
+		/* Everyone else gets kicked off. */
+		migrate_all_tasks();
+
+	return err;
+}
+
+int cpu_down(unsigned int cpu)
+{
+	int err;
+	struct task_struct *p;
+
+	if ((err = lock_cpu_hotplug_interruptible()) != 0)
+		return err;
+
+	if (num_online_cpus() == 1) {
+		err = -EBUSY;
+		goto out;
+	}
+
+	if (!cpu_online(cpu)) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	p = __stop_machine_run(take_cpu_down, NULL, cpu);
+	if (IS_ERR(p)) {
+		err = PTR_ERR(p);
+		goto out;
+	}
+
+	if (cpu_online(cpu))
+		goto out_thread;
+
+	check_for_tasks(cpu, p);
+
+	/* Wait for it to sleep (leaving idle task). */
+	while (!idle_cpu(cpu))
+		yield();
+
+	/* This actually kills the CPU. */
+	__cpu_die(cpu);
+
+	/* Move it here so it can run. */
+	kthread_bind(p, smp_processor_id());
+
+	/* CPU is completely dead: tell everyone.  Too late to complain. */
+	if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu)
+	    == NOTIFY_BAD)
+		BUG();
+
+	cpu_run_sbin_hotplug(cpu, "offline");
+
+out_thread:
+	err = kthread_stop(p);
+out:
+	unlock_cpu_hotplug();
+	return err;
+}
+#else
+static inline int cpu_run_sbin_hotplug(unsigned int cpu, const char *action)
+{
+	return 0;
 }
+#endif /*CONFIG_HOTPLUG_CPU*/
 
 int __devinit cpu_up(unsigned int cpu)
 {
diff -Nru a/kernel/exec_domain.c b/kernel/exec_domain.c
--- a/kernel/exec_domain.c	Sat Apr  3 19:38:44 2004
+++ b/kernel/exec_domain.c	Sat Apr  3 19:38:44 2004
@@ -170,7 +170,7 @@
 		fsp = copy_fs_struct(current->fs);
 		if (fsp == NULL) {
 			module_put(ep->module);
-			return -ENOMEM;;
+			return -ENOMEM;
 		}
 
 		task_lock(current);
@@ -213,7 +213,7 @@
 asmlinkage long
 sys_personality(u_long personality)
 {
-	u_long old = current->personality;;
+	u_long old = current->personality;
 
 	if (personality != 0xffffffff) {
 		set_personality(personality);
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Sat Apr  3 19:38:55 2004
+++ b/kernel/exit.c	Sat Apr  3 19:38:55 2004
@@ -1146,7 +1146,8 @@
 	return retval;
 }
 
-#if !defined(__alpha__) && !defined(__ia64__) && !defined(__arm__)
+#if !defined(__alpha__) && !defined(__ia64__) && \
+    !defined(__arm__) && !defined(__s390__)
 
 /*
  * sys_waitpid() remains for compatibility. waitpid() should be
diff -Nru a/kernel/kthread.c b/kernel/kthread.c
--- a/kernel/kthread.c	Sat Apr  3 19:38:55 2004
+++ b/kernel/kthread.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 	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 @@
 	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 @@
 	} 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 @@
 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 -Nru a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c	Sat Apr  3 19:38:54 2004
+++ b/kernel/module.c	Sat Apr  3 19:38:54 2004
@@ -596,7 +596,9 @@
 		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 @@
 		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,13 +1524,11 @@
 	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) {
diff -Nru a/kernel/ptrace.c b/kernel/ptrace.c
--- a/kernel/ptrace.c	Sat Apr  3 19:38:57 2004
+++ b/kernel/ptrace.c	Sat Apr  3 19:38:57 2004
@@ -168,7 +168,7 @@
 		int bytes, ret, offset;
 		void *maddr;
 
-		ret = get_user_pages(current, mm, addr, 1,
+		ret = get_user_pages(tsk, mm, addr, 1,
 				write, 1, &page, &vma);
 		if (ret <= 0)
 			break;
diff -Nru a/kernel/rcupdate.c b/kernel/rcupdate.c
--- a/kernel/rcupdate.c	Sat Apr  3 19:38:40 2004
+++ b/kernel/rcupdate.c	Sat Apr  3 19:38:40 2004
@@ -110,6 +110,7 @@
 	    !cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
 		return;
 	}
+	/* Can't change, since spin lock held. */
 	rcu_ctrlblk.rcu_cpu_mask = cpu_online_map;
 }
 
@@ -154,6 +155,60 @@
 }
 
 
+#ifdef CONFIG_HOTPLUG_CPU
+
+/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing
+ * locking requirements, the list it's pulling from has to belong to a cpu
+ * which is dead and hence not processing interrupts.
+ */
+static void rcu_move_batch(struct list_head *list)
+{
+	struct list_head *entry;
+	int cpu = smp_processor_id();
+
+	local_irq_disable();
+	while (!list_empty(list)) {
+		entry = list->next;
+		list_del(entry);
+		list_add_tail(entry, &RCU_nxtlist(cpu));
+	}
+	local_irq_enable();
+}
+
+static void rcu_offline_cpu(int cpu)
+{
+	/* if the cpu going offline owns the grace period
+	 * we can block indefinitely waiting for it, so flush
+	 * it here
+	 */
+	spin_lock_irq(&rcu_ctrlblk.mutex);
+	if (!rcu_ctrlblk.rcu_cpu_mask)
+		goto unlock;
+
+	cpu_clear(cpu, rcu_ctrlblk.rcu_cpu_mask);
+	if (cpus_empty(rcu_ctrlblk.rcu_cpu_mask)) {
+		rcu_ctrlblk.curbatch++;
+		/* We may avoid calling start batch if
+		 * we are starting the batch only
+		 * because of the DEAD CPU (the current
+		 * CPU will start a new batch anyway for
+		 * the callbacks we will move to current CPU).
+		 * However, we will avoid this optimisation
+		 * for now.
+		 */
+		rcu_start_batch(rcu_ctrlblk.maxbatch);
+	}
+unlock:
+	spin_unlock_irq(&rcu_ctrlblk.mutex);
+
+	rcu_move_batch(&RCU_curlist(cpu));
+	rcu_move_batch(&RCU_nxtlist(cpu));
+
+	tasklet_kill_immediate(&RCU_tasklet(cpu), cpu);
+}
+
+#endif
+
 /*
  * This does the RCU processing work from tasklet context. 
  */
@@ -214,7 +269,11 @@
 	case CPU_UP_PREPARE:
 		rcu_online_cpu(cpu);
 		break;
-	/* Space reserved for CPU_OFFLINE :) */
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		rcu_offline_cpu(cpu);
+		break;
+#endif
 	default:
 		break;
 	}
diff -Nru a/kernel/resource.c b/kernel/resource.c
--- a/kernel/resource.c	Sat Apr  3 19:38:45 2004
+++ b/kernel/resource.c	Sat Apr  3 19:38:45 2004
@@ -335,6 +335,7 @@
 	/* existing resource overlaps end of new resource */
 	if (next->end > new->end) {
 		parent = next;
+		result = 0;
 		goto begin;
 	}
 
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Sat Apr  3 19:38:55 2004
+++ b/kernel/sched.c	Sat Apr  3 19:38:55 2004
@@ -201,8 +201,9 @@
  */
 struct runqueue {
 	spinlock_t lock;
-	unsigned long nr_running, nr_switches, expired_timestamp,
-		      nr_uninterruptible, timestamp_last_tick;
+	unsigned long long nr_switches;
+	unsigned long nr_running, expired_timestamp, nr_uninterruptible,
+		timestamp_last_tick;
 	task_t *curr, *idle;
 	struct mm_struct *prev_mm;
 	prio_array_t *active, *expired, arrays[2];
@@ -593,28 +594,21 @@
 {
 	unsigned long flags;
 	runqueue_t *rq;
+	int preempted;
 
 repeat:
-	preempt_disable();
-	rq = task_rq(p);
-	if (unlikely(task_running(rq, p))) {
-		cpu_relax();
-		/*
-		 * enable/disable preemption just to make this
-		 * a preemption point - we are busy-waiting
-		 * anyway.
-		 */
-		preempt_enable();
-		goto repeat;
-	}
 	rq = task_rq_lock(p, &flags);
-	if (unlikely(task_running(rq, p))) {
+	/* Must be off runqueue entirely, not preempted. */
+	if (unlikely(p->array)) {
+		/* If it's preempted, we yield.  It could be a while. */
+		preempted = !task_running(rq, p);
 		task_rq_unlock(rq, &flags);
-		preempt_enable();
+		cpu_relax();
+		if (preempted)
+			yield();
 		goto repeat;
 	}
 	task_rq_unlock(rq, &flags);
-	preempt_enable();
 }
 
 /***
@@ -672,8 +666,8 @@
 			if (unlikely(sync && !task_running(rq, p) &&
 				(task_cpu(p) != smp_processor_id()) &&
 					cpu_isset(smp_processor_id(),
-							p->cpus_allowed))) {
-
+							p->cpus_allowed) &&
+					!cpu_is_offline(smp_processor_id()))) {
 				set_task_cpu(p, smp_processor_id());
 				task_rq_unlock(rq, &flags);
 				goto repeat_lock_task;
@@ -950,9 +944,9 @@
 	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;
@@ -1018,6 +1012,7 @@
 	unsigned long flags;
 	cpumask_t old_mask, new_mask = cpumask_of_cpu(dest_cpu);
 
+	lock_cpu_hotplug();
 	rq = task_rq_lock(p, &flags);
 	old_mask = p->cpus_allowed;
 	if (!cpu_isset(dest_cpu, old_mask) || !cpu_online(dest_cpu))
@@ -1041,6 +1036,7 @@
 	}
 out:
 	task_rq_unlock(rq, &flags);
+	unlock_cpu_hotplug();
 }
 
 /*
@@ -1305,6 +1301,9 @@
 	struct list_head *head, *curr;
 	task_t *tmp;
 
+	if (cpu_is_offline(this_cpu))
+		goto out;
+
 	busiest = find_busiest_queue(this_rq, this_cpu, idle,
 				     &imbalance, cpumask);
 	if (!busiest)
@@ -1679,7 +1678,7 @@
 	queue = array->queue + idx;
 	next = list_entry(queue->next, task_t, run_list);
 
-	if (next->activated > 0) {
+	if (!rt_task(next) && next->activated > 0) {
 		unsigned long long delta = now - next->timestamp;
 
 		if (next->activated == 1)
@@ -2103,6 +2102,18 @@
 	return pid ? find_task_by_pid(pid) : current;
 }
 
+/* Actually do priority change: must hold rq lock. */
+static void __setscheduler(struct task_struct *p, int policy, int prio)
+{
+	BUG_ON(p->array);
+	p->policy = policy;
+	p->rt_priority = prio;
+	if (policy != SCHED_NORMAL)
+		p->prio = MAX_USER_RT_PRIO-1 - p->rt_priority;
+	else
+		p->prio = p->static_prio;
+}
+
 /*
  * setscheduler - change the scheduling policy and/or RT priority of a thread.
  */
@@ -2175,13 +2186,8 @@
 	if (array)
 		deactivate_task(p, task_rq(p));
 	retval = 0;
-	p->policy = policy;
-	p->rt_priority = lp.sched_priority;
 	oldprio = p->prio;
-	if (policy != SCHED_NORMAL)
-		p->prio = MAX_USER_RT_PRIO-1 - p->rt_priority;
-	else
-		p->prio = p->static_prio;
+	__setscheduler(p, policy, lp.sched_priority);
 	if (array) {
 		__activate_task(p, task_rq(p));
 		/*
@@ -2312,11 +2318,13 @@
 	if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask)))
 		return -EFAULT;
 
+	lock_cpu_hotplug();
 	read_lock(&tasklist_lock);
 
 	p = find_process_by_pid(pid);
 	if (!p) {
 		read_unlock(&tasklist_lock);
+		unlock_cpu_hotplug();
 		return -ESRCH;
 	}
 
@@ -2337,6 +2345,7 @@
 
 out_unlock:
 	put_task_struct(p);
+	unlock_cpu_hotplug();
 	return retval;
 }
 
@@ -2731,11 +2740,9 @@
 static void move_task_away(struct task_struct *p, int dest_cpu)
 {
 	runqueue_t *rq_dest;
-	unsigned long flags;
 
 	rq_dest = cpu_rq(dest_cpu);
 
-	local_irq_save(flags);
 	double_rq_lock(this_rq(), rq_dest);
 	if (task_cpu(p) != smp_processor_id())
 		goto out; /* Already moved */
@@ -2751,7 +2758,6 @@
 
 out:
 	double_rq_unlock(this_rq(), rq_dest);
-	local_irq_restore(flags);
 }
 
 /*
@@ -2761,16 +2767,10 @@
  */
 static int migration_thread(void * data)
 {
-	/* Marking "param" __user is ok, since we do a set_fs(KERNEL_DS); */
-	struct sched_param __user param = { .sched_priority = MAX_RT_PRIO-1 };
 	runqueue_t *rq;
 	int cpu = (long)data;
-	int ret;
-
-	BUG_ON(smp_processor_id() != cpu);
-	ret = setscheduler(0, SCHED_FIFO, &param);
 
-	rq = this_rq();
+	rq = cpu_rq(cpu);
 	BUG_ON(rq->migration_thread != current);
 
 	while (!kthread_should_stop()) {
@@ -2790,15 +2790,73 @@
 		}
 		req = list_entry(head->next, migration_req_t, list);
 		list_del_init(head->next);
-		spin_unlock_irq(&rq->lock);
+		spin_unlock(&rq->lock);
 
 		move_task_away(req->task,
 			       any_online_cpu(req->task->cpus_allowed));
+		local_irq_enable();
 		complete(&req->done);
 	}
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* migrate_all_tasks - function to migrate all the tasks from the
+ * current cpu caller must have already scheduled this to the target
+ * cpu via set_cpus_allowed.  Machine is stopped.  */
+void migrate_all_tasks(void)
+{
+	struct task_struct *tsk, *t;
+	int dest_cpu, src_cpu;
+	unsigned int node;
+
+	/* We're nailed to this CPU. */
+	src_cpu = smp_processor_id();
+
+	/* Not required, but here for neatness. */
+	write_lock(&tasklist_lock);
+
+	/* watch out for per node tasks, let's stay on this node */
+	node = cpu_to_node(src_cpu);
+
+	do_each_thread(t, tsk) {
+		cpumask_t mask;
+		if (tsk == current)
+			continue;
+
+		if (task_cpu(tsk) != src_cpu)
+			continue;
+
+		/* Figure out where this task should go (attempting to
+		 * keep it on-node), and check if it can be migrated
+		 * as-is.  NOTE that kernel threads bound to more than
+		 * one online cpu will be migrated. */
+		mask = node_to_cpumask(node);
+		cpus_and(mask, mask, tsk->cpus_allowed);
+		dest_cpu = any_online_cpu(mask);
+		if (dest_cpu == NR_CPUS)
+			dest_cpu = any_online_cpu(tsk->cpus_allowed);
+		if (dest_cpu == NR_CPUS) {
+			cpus_clear(tsk->cpus_allowed);
+			cpus_complement(tsk->cpus_allowed);
+			dest_cpu = any_online_cpu(tsk->cpus_allowed);
+
+			/* Don't tell them about moving exiting tasks
+			   or kernel threads (both mm NULL), since
+			   they never leave kernel. */
+			if (tsk->mm && printk_ratelimit())
+				printk(KERN_INFO "process %d (%s) no "
+				       "longer affine to cpu%d\n",
+				       tsk->pid, tsk->comm, src_cpu);
+		}
+
+		move_task_away(tsk, dest_cpu);
+	} while_each_thread(t, tsk);
+
+	write_unlock(&tasklist_lock);
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 /*
  * migration_call - callback that gets triggered when a CPU is added.
  * Here we can start up the necessary migration thread for the new CPU.
@@ -2808,6 +2866,8 @@
 {
 	int cpu = (long)hcpu;
 	struct task_struct *p;
+	struct runqueue *rq;
+	unsigned long flags;
 
 	switch (action) {
 	case CPU_UP_PREPARE:
@@ -2815,23 +2875,32 @@
 		if (IS_ERR(p))
 			return NOTIFY_BAD;
 		kthread_bind(p, cpu);
+		/* Must be high prio: stop_machine expects to yield to it. */
+		rq = task_rq_lock(p, &flags);
+		__setscheduler(p, SCHED_FIFO, MAX_RT_PRIO-1);
+		task_rq_unlock(rq, &flags);
 		cpu_rq(cpu)->migration_thread = p;
 		break;
 	case CPU_ONLINE:
 		/* Strictly unneccessary, as first user will wake it. */
 		wake_up_process(cpu_rq(cpu)->migration_thread);
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_UP_CANCELED:
+		/* Unbind it from offline cpu so it can run.  Fall thru. */
+		kthread_bind(cpu_rq(cpu)->migration_thread,smp_processor_id());
+	case CPU_DEAD:
+		kthread_stop(cpu_rq(cpu)->migration_thread);
+		cpu_rq(cpu)->migration_thread = NULL;
+ 		BUG_ON(cpu_rq(cpu)->nr_running != 0);
+ 		break;
+#endif
 	}
 	return NOTIFY_OK;
 }
 
-/*
- * We want this after the other threads, so they can use set_cpus_allowed
- * from their CPU_OFFLINE callback
- */
 static struct notifier_block __devinitdata migration_notifier = {
 	.notifier_call = migration_call,
-	.priority = -10,
 };
 
 int __init migration_init(void)
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Sat Apr  3 19:38:43 2004
+++ b/kernel/signal.c	Sat Apr  3 19:38:43 2004
@@ -157,7 +157,7 @@
 	 sigtestsetmask(&current->signal->shared_pending.signal, \
 						  M(SIGCONT) | M(SIGKILL)))
 
-static inline int sig_ignored(struct task_struct *t, int sig)
+static int sig_ignored(struct task_struct *t, int sig)
 {
 	void * handler;
 
@@ -532,7 +532,7 @@
  * No need to set need_resched since signal event passing
  * goes through ->blocked
  */
-inline void signal_wake_up(struct task_struct *t, int resume)
+void signal_wake_up(struct task_struct *t, int resume)
 {
 	unsigned int mask;
 
@@ -837,7 +837,7 @@
 	 && (task_curr(p) || !signal_pending(p)))
 
 
-static inline void
+static void
 __group_complete_signal(int sig, struct task_struct *p, unsigned int mask)
 {
 	struct task_struct *t;
@@ -940,7 +940,7 @@
 	return;
 }
 
-static inline int
+static int
 __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
 	unsigned int mask;
@@ -1051,17 +1051,23 @@
 	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
@@ -1369,7 +1375,7 @@
  * Joy. Or not. Pthread wants us to wake up every thread
  * in our parent group.
  */
-static inline void __wake_up_parent(struct task_struct *p,
+static void __wake_up_parent(struct task_struct *p,
 				    struct task_struct *parent)
 {
 	struct task_struct *tsk = parent;
@@ -2476,7 +2482,8 @@
 #endif /* __sparc__ */
 #endif
 
-#if !defined(__alpha__) && !defined(__ia64__) && !defined(__arm__)
+#if !defined(__alpha__) && !defined(__ia64__) && \
+    !defined(__arm__) && !defined(__s390__)
 /*
  * For backwards compatibility.  Functionality superseded by sigprocmask.
  */
diff -Nru a/kernel/softirq.c b/kernel/softirq.c
--- a/kernel/softirq.c	Sat Apr  3 19:38:42 2004
+++ b/kernel/softirq.c	Sat Apr  3 19:38:42 2004
@@ -308,13 +308,9 @@
 
 static int ksoftirqd(void * __bind_cpu)
 {
-	int cpu = (int) (long) __bind_cpu;
-
 	set_user_nice(current, 19);
 	current->flags |= PF_IOTHREAD;
 
-	BUG_ON(smp_processor_id() != cpu);
-
 	set_current_state(TASK_INTERRUPTIBLE);
 
 	while (!kthread_should_stop()) {
@@ -324,15 +320,86 @@
 		__set_current_state(TASK_RUNNING);
 
 		while (local_softirq_pending()) {
+			/* Preempt disable stops cpu going offline.
+			   If already offline, we'll be on wrong CPU:
+			   don't process */
+			preempt_disable();
+			if (cpu_is_offline((long)__bind_cpu))
+				goto wait_to_die;
 			do_softirq();
+			preempt_enable();
 			cond_resched();
 		}
 
-		__set_current_state(TASK_INTERRUPTIBLE);
+		set_current_state(TASK_INTERRUPTIBLE);
 	}
+	__set_current_state(TASK_RUNNING);
 	return 0;
+
+wait_to_die:
+	preempt_enable();
+	/* Wait for kthread_stop */
+	set_current_state(TASK_INTERRUPTIBLE);
+	while (!kthread_should_stop()) {
+		schedule();
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+	__set_current_state(TASK_RUNNING);
+	return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * tasklet_kill_immediate is called to remove a tasklet which can already be
+ * scheduled for execution on @cpu.
+ *
+ * Unlike tasklet_kill, this function removes the tasklet
+ * _immediately_, even if the tasklet is in TASKLET_STATE_SCHED state.
+ *
+ * When this function is called, @cpu must be in the CPU_DEAD state.
+ */
+void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu)
+{
+	struct tasklet_struct **i;
+
+	BUG_ON(cpu_online(cpu));
+	BUG_ON(test_bit(TASKLET_STATE_RUN, &t->state));
+
+	if (!test_bit(TASKLET_STATE_SCHED, &t->state))
+		return;
+
+	/* CPU is dead, so no lock needed. */
+	for (i = &per_cpu(tasklet_vec, cpu).list; *i; i = &(*i)->next) {
+		if (*i == t) {
+			*i = t->next;
+			return;
+		}
+	}
+	BUG();
 }
 
+static void takeover_tasklets(unsigned int cpu)
+{
+	struct tasklet_struct **i;
+
+	/* CPU is dead, so no lock needed. */
+	local_irq_disable();
+
+	/* Find end, append list for that CPU. */
+	for (i = &__get_cpu_var(tasklet_vec).list; *i; i = &(*i)->next);
+	*i = per_cpu(tasklet_vec, cpu).list;
+	per_cpu(tasklet_vec, cpu).list = NULL;
+	raise_softirq_irqoff(TASKLET_SOFTIRQ);
+
+	for (i = &__get_cpu_var(tasklet_hi_vec).list; *i; i = &(*i)->next);
+	*i = per_cpu(tasklet_hi_vec, cpu).list;
+	per_cpu(tasklet_hi_vec, cpu).list = NULL;
+	raise_softirq_irqoff(HI_SOFTIRQ);
+
+	local_irq_enable();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __devinit cpu_callback(struct notifier_block *nfb,
 				  unsigned long action,
 				  void *hcpu)
@@ -349,13 +416,23 @@
 			printk("ksoftirqd for %i failed\n", hotcpu);
 			return NOTIFY_BAD;
 		}
-		per_cpu(ksoftirqd, hotcpu) = p;
 		kthread_bind(p, hotcpu);
   		per_cpu(ksoftirqd, hotcpu) = p;
  		break;
 	case CPU_ONLINE:
 		wake_up_process(per_cpu(ksoftirqd, hotcpu));
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_UP_CANCELED:
+		/* Unbind so it can run.  Fall thru. */
+		kthread_bind(per_cpu(ksoftirqd, hotcpu), smp_processor_id());
+	case CPU_DEAD:
+		p = per_cpu(ksoftirqd, hotcpu);
+		per_cpu(ksoftirqd, hotcpu) = NULL;
+		kthread_stop(p);
+		takeover_tasklets(hotcpu);
+		break;
+#endif /* CONFIG_HOTPLUG_CPU */
  	}
 	return NOTIFY_OK;
 }
diff -Nru a/kernel/stop_machine.c b/kernel/stop_machine.c
--- a/kernel/stop_machine.c	Sat Apr  3 19:38:41 2004
+++ b/kernel/stop_machine.c	Sat Apr  3 19:38:41 2004
@@ -149,10 +149,12 @@
 	complete(&smdata->done);
 
 	/* Wait for kthread_stop */
+	__set_current_state(TASK_INTERRUPTIBLE);
 	while (!kthread_should_stop()) {
-		__set_current_state(TASK_INTERRUPTIBLE);
 		schedule();
+		__set_current_state(TASK_INTERRUPTIBLE);
 	}
+	__set_current_state(TASK_RUNNING);
 	return ret;
 }
 
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Sat Apr  3 19:38:41 2004
+++ b/kernel/sysctl.c	Sat Apr  3 19:38:41 2004
@@ -736,6 +736,14 @@
 		.strategy	= &sysctl_intvec,
 		.extra1		= &zero,
 	},
+	{
+		.ctl_name	= VM_MAX_MAP_COUNT,
+		.procname	= "max_map_count",
+		.data		= &sysctl_max_map_count,
+		.maxlen		= sizeof(sysctl_max_map_count),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec
+	},
 	{ .ctl_name = 0 }
 };
 
@@ -1004,7 +1012,8 @@
 	 * zero, proceed with automatic r/w */
 	if (table->data && table->maxlen) {
 		if (oldval && oldlenp) {
-			get_user(len, oldlenp);
+			if (get_user(len, oldlenp))
+				return -EFAULT;
 			if (len) {
 				if (len > table->maxlen)
 					len = table->maxlen;
@@ -1303,7 +1312,7 @@
 		len = 0;
 		p = buffer;
 		while (len < *lenp) {
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (c == 0 || c == '\n')
 				break;
@@ -1470,7 +1479,7 @@
 		p = (char *) buffer;
 		while (left) {
 			char c;
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (!isspace(c))
 				break;
@@ -1705,7 +1714,7 @@
 		p = (char *) buffer;
 		while (left) {
 			char c;
-			if(get_user(c, p++))
+			if (get_user(c, p++))
 				return -EFAULT;
 			if (!isspace(c))
 				break;
@@ -1930,7 +1939,7 @@
 		return -ENOTDIR;
 	
 	if (oldval && oldlenp) {
-		if(get_user(len, oldlenp))
+		if (get_user(len, oldlenp))
 			return -EFAULT;
 		if (len) {
 			l = strlen(table->data);
@@ -1987,7 +1996,8 @@
 
 		for (i = 0; i < length; i++) {
 			int value;
-			get_user(value, vec + i);
+			if (get_user(value, vec + i))
+				return -EFAULT;
 			if (min && value < min[i])
 				return -EINVAL;
 			if (max && value > max[i])
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Sat Apr  3 19:38:55 2004
+++ b/kernel/timer.c	Sat Apr  3 19:38:55 2004
@@ -677,7 +677,6 @@
 	if (xtime.tv_nsec >= 1000000000) {
 	    xtime.tv_nsec -= 1000000000;
 	    xtime.tv_sec++;
-	    time_interpolator_update(NSEC_PER_SEC);
 	    second_overflow();
 	}
 }
@@ -1060,7 +1059,7 @@
 static long nanosleep_restart(struct restart_block *restart)
 {
 	unsigned long expire = restart->arg0, now = jiffies;
-	struct timespec *rmtp = (struct timespec *) restart->arg1;
+	struct timespec __user *rmtp = (struct timespec __user *) restart->arg1;
 	long ret;
 
 	/* Did it expire while we handled signals? */
@@ -1083,7 +1082,7 @@
 	return ret;
 }
 
-asmlinkage long sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
+asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp)
 {
 	struct timespec t;
 	unsigned long expire;
@@ -1223,7 +1222,73 @@
 
 	base->timer_jiffies = jiffies;
 }
-	
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int migrate_timer_list(tvec_base_t *new_base, struct list_head *head)
+{
+	struct timer_list *timer;
+
+	while (!list_empty(head)) {
+		timer = list_entry(head->next, struct timer_list, entry);
+		/* We're locking backwards from __mod_timer order here,
+		   beware deadlock. */
+		if (!spin_trylock(&timer->lock))
+			return 0;
+		list_del(&timer->entry);
+		internal_add_timer(new_base, timer);
+		timer->base = new_base;
+		spin_unlock(&timer->lock);
+	}
+	return 1;
+}
+
+static void __devinit migrate_timers(int cpu)
+{
+	tvec_base_t *old_base;
+	tvec_base_t *new_base;
+	int i;
+
+	BUG_ON(cpu_online(cpu));
+	old_base = &per_cpu(tvec_bases, cpu);
+	new_base = &get_cpu_var(tvec_bases);
+
+	local_irq_disable();
+again:
+	/* Prevent deadlocks via ordering by old_base < new_base. */
+	if (old_base < new_base) {
+		spin_lock(&new_base->lock);
+		spin_lock(&old_base->lock);
+	} else {
+		spin_lock(&old_base->lock);
+		spin_lock(&new_base->lock);
+	}
+
+	if (old_base->running_timer)
+		BUG();
+	for (i = 0; i < TVR_SIZE; i++)
+		if (!migrate_timer_list(new_base, old_base->tv1.vec + i))
+			goto unlock_again;
+	for (i = 0; i < TVN_SIZE; i++)
+		if (!migrate_timer_list(new_base, old_base->tv2.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv3.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv4.vec + i)
+		    || !migrate_timer_list(new_base, old_base->tv5.vec + i))
+			goto unlock_again;
+	spin_unlock(&old_base->lock);
+	spin_unlock(&new_base->lock);
+	local_irq_enable();
+	put_cpu_var(tvec_bases);
+	return;
+
+unlock_again:
+	/* Avoid deadlock with __mod_timer, by backing off. */
+	spin_unlock(&old_base->lock);
+	spin_unlock(&new_base->lock);
+	cpu_relax();
+	goto again;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __devinit timer_cpu_notify(struct notifier_block *self, 
 				unsigned long action, void *hcpu)
 {
@@ -1232,6 +1297,11 @@
 	case CPU_UP_PREPARE:
 		init_timers_cpu(cpu);
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		migrate_timers(cpu);
+		break;
+#endif
 	default:
 		break;
 	}
diff -Nru a/kernel/uid16.c b/kernel/uid16.c
--- a/kernel/uid16.c	Sat Apr  3 19:38:43 2004
+++ b/kernel/uid16.c	Sat Apr  3 19:38:43 2004
@@ -17,12 +17,12 @@
 
 #include <asm/uaccess.h>
 
-asmlinkage long sys_chown16(const char * filename, old_uid_t user, old_gid_t group)
+asmlinkage long sys_chown16(const char __user * filename, old_uid_t user, old_gid_t group)
 {
 	return sys_chown(filename, low2highuid(user), low2highgid(group));
 }
 
-asmlinkage long sys_lchown16(const char * filename, old_uid_t user, old_gid_t group)
+asmlinkage long sys_lchown16(const char __user * filename, old_uid_t user, old_gid_t group)
 {
 	return sys_lchown(filename, low2highuid(user), low2highgid(group));
 }
@@ -58,7 +58,7 @@
 		low2highuid(suid));
 }
 
-asmlinkage long sys_getresuid16(old_uid_t *ruid, old_uid_t *euid, old_uid_t *suid)
+asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid, old_uid_t __user *suid)
 {
 	int retval;
 
@@ -75,7 +75,7 @@
 		low2highgid(sgid));
 }
 
-asmlinkage long sys_getresgid16(old_gid_t *rgid, old_gid_t *egid, old_gid_t *sgid)
+asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid, old_gid_t __user *sgid)
 {
 	int retval;
 
diff -Nru a/kernel/workqueue.c b/kernel/workqueue.c
--- a/kernel/workqueue.c	Sat Apr  3 19:38:56 2004
+++ b/kernel/workqueue.c	Sat Apr  3 19:38:56 2004
@@ -22,6 +22,8 @@
 #include <linux/completion.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
 #include <linux/kthread.h>
 
 /*
@@ -47,6 +49,7 @@
 	struct workqueue_struct *wq;
 	task_t *thread;
 
+	int run_depth;		/* Detect run_workqueue() recursion depth */
 } ____cacheline_aligned;
 
 /*
@@ -55,8 +58,22 @@
  */
 struct workqueue_struct {
 	struct cpu_workqueue_struct cpu_wq[NR_CPUS];
+	const char *name;
+	struct list_head list;
 };
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* All the workqueues on the system, for hotplug cpu to add/remove
+   threads to each one as cpus come/go.  Protected by cpucontrol
+   sem. */
+static LIST_HEAD(workqueues);
+#define add_workqueue(wq) list_add(&(wq)->list, &workqueues)
+#define del_workqueue(wq) list_del(&(wq)->list)
+#else
+#define add_workqueue(wq)
+#define del_workqueue(wq)
+#endif /* CONFIG_HOTPLUG_CPU */
+
 /* Preempt must be disabled. */
 static void __queue_work(struct cpu_workqueue_struct *cwq,
 			 struct work_struct *work)
@@ -129,6 +146,13 @@
 	 * 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,13 +170,13 @@
 		cwq->remove_sequence++;
 		wake_up(&cwq->work_done);
 	}
+	cwq->run_depth--;
 	spin_unlock_irqrestore(&cwq->lock, flags);
 }
 
 static int worker_thread(void *__cwq)
 {
 	struct cpu_workqueue_struct *cwq = __cwq;
-	int cpu = cwq - cwq->wq->cpu_wq;
 	DECLARE_WAITQUEUE(wait, current);
 	struct k_sigaction sa;
 	sigset_t blocked;
@@ -160,7 +184,6 @@
 	current->flags |= PF_IOTHREAD;
 
 	set_user_nice(current, -10);
-	BUG_ON(smp_processor_id() != cpu);
 
 	/* Block and flush all signals */
 	sigfillset(&blocked);
@@ -210,6 +233,7 @@
 
 	might_sleep();
 
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		DEFINE_WAIT(wait);
 		long sequence_needed;
@@ -218,6 +242,14 @@
 			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;
 
@@ -231,11 +263,10 @@
 		finish_wait(&cwq->work_done, &wait);
 		spin_unlock_irq(&cwq->lock);
 	}
+	unlock_cpu_hotplug();
 }
 
-static int create_workqueue_thread(struct workqueue_struct *wq,
-				   const char *name,
-				   int cpu)
+static int create_workqueue_thread(struct workqueue_struct *wq, int cpu)
 {
 	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
 	struct task_struct *p;
@@ -249,7 +280,7 @@
 	init_waitqueue_head(&cwq->more_work);
 	init_waitqueue_head(&cwq->work_done);
 
-	p = kthread_create(worker_thread, cwq, "%s/%d", name, cpu);
+	p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu);
 	if (IS_ERR(p))
 		return PTR_ERR(p);
 	cwq->thread = p;
@@ -267,15 +298,21 @@
 	wq = kmalloc(sizeof(*wq), GFP_KERNEL);
 	if (!wq)
 		return NULL;
+	memset(wq, 0, sizeof(*wq));
 
+	wq->name = name;
+	/* We don't need the distraction of CPUs appearing and vanishing. */
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (!cpu_online(cpu))
 			continue;
-		if (create_workqueue_thread(wq, name, cpu) < 0)
+		if (create_workqueue_thread(wq, cpu) < 0)
 			destroy = 1;
 		else
 			wake_up_process(wq->cpu_wq[cpu].thread);
 	}
+	add_workqueue(wq);
+
 	/*
 	 * Was there any error during startup? If yes then clean up:
 	 */
@@ -283,16 +320,23 @@
 		destroy_workqueue(wq);
 		wq = NULL;
 	}
+	unlock_cpu_hotplug();
 	return wq;
 }
 
 static void cleanup_workqueue_thread(struct workqueue_struct *wq, int cpu)
 {
 	struct cpu_workqueue_struct *cwq;
+	unsigned long flags;
+	struct task_struct *p;
 
 	cwq = wq->cpu_wq + cpu;
-	if (cwq->thread)
-		kthread_stop(cwq->thread);
+	spin_lock_irqsave(&cwq->lock, flags);
+	p = cwq->thread;
+	cwq->thread = NULL;
+	spin_unlock_irqrestore(&cwq->lock, flags);
+	if (p)
+		kthread_stop(p);
 }
 
 void destroy_workqueue(struct workqueue_struct *wq)
@@ -301,10 +345,14 @@
 
 	flush_workqueue(wq);
 
+	/* We don't need the distraction of CPUs appearing and vanishing. */
+	lock_cpu_hotplug();
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (cpu_online(cpu))
 			cleanup_workqueue_thread(wq, cpu);
 	}
+	del_workqueue(wq);
+	unlock_cpu_hotplug();
 	kfree(wq);
 }
 
@@ -333,20 +381,88 @@
 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;
+	cwq = keventd_wq->cpu_wq + cpu;
+	if (current == cwq->thread)
+		ret = 1;
+
+	return ret;
+
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+/* Take the work from this (downed) CPU. */
+static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
+{
+	struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu;
+	LIST_HEAD(list);
+	struct work_struct *work;
+
+	spin_lock_irq(&cwq->lock);
+	list_splice_init(&cwq->worklist, &list);
+
+	while (!list_empty(&list)) {
+		printk("Taking work for %s\n", wq->name);
+		work = list_entry(list.next,struct work_struct,entry);
+		list_del(&work->entry);
+		__queue_work(wq->cpu_wq + smp_processor_id(), work);
 	}
-	return 0;
+	spin_unlock_irq(&cwq->lock);
+}
+
+/* We're holding the cpucontrol mutex here */
+static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
+				  unsigned long action,
+				  void *hcpu)
+{
+	unsigned int hotcpu = (unsigned long)hcpu;
+	struct workqueue_struct *wq;
+
+	switch (action) {
+	case CPU_UP_PREPARE:
+		/* Create a new workqueue thread for it. */
+		list_for_each_entry(wq, &workqueues, list) {
+			if (create_workqueue_thread(wq, hotcpu) < 0) {
+				printk("workqueue for %i failed\n", hotcpu);
+				return NOTIFY_BAD;
+			}
+		}
+		break;
+
+	case CPU_ONLINE:
+		/* Kick off worker threads. */
+		list_for_each_entry(wq, &workqueues, list)
+			wake_up_process(wq->cpu_wq[hotcpu].thread);
+		break;
+
+	case CPU_UP_CANCELED:
+		list_for_each_entry(wq, &workqueues, list) {
+			/* Unbind so it can run. */
+			kthread_bind(wq->cpu_wq[hotcpu].thread,
+				     smp_processor_id());
+			cleanup_workqueue_thread(wq, hotcpu);
+		}
+		break;
+
+	case CPU_DEAD:
+		list_for_each_entry(wq, &workqueues, list)
+			cleanup_workqueue_thread(wq, hotcpu);
+		list_for_each_entry(wq, &workqueues, list)
+			take_over_work(wq, hotcpu);
+		break;
+	}
+
+	return NOTIFY_OK;
 }
+#endif
 
 void init_workqueues(void)
 {
+	hotcpu_notifier(workqueue_cpu_callback, 0);
 	keventd_wq = create_workqueue("events");
 	BUG_ON(!keventd_wq);
 }
diff -Nru a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile	Sat Apr  3 19:38:41 2004
+++ b/lib/Makefile	Sat Apr  3 19:38:41 2004
@@ -8,6 +8,9 @@
 	 kobject.o idr.o div64.o parser.o int_sqrt.o \
 	 bitmap.o extable.o
 
+# hack for now till some static code uses krefs, then it can move up above...
+obj-y += kref.o
+
 lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
 lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
 
diff -Nru a/lib/bitmap.c b/lib/bitmap.c
--- a/lib/bitmap.c	Sat Apr  3 19:38:55 2004
+++ b/lib/bitmap.c	Sat Apr  3 19:38:55 2004
@@ -47,7 +47,7 @@
 int bitmap_equal(const unsigned long *bitmap1,
 		unsigned long *bitmap2, int bits)
 {
-	int k, lim = bits/BITS_PER_LONG;;
+	int k, lim = bits/BITS_PER_LONG;
 	for (k = 0; k < lim; ++k)
 		if (bitmap1[k] != bitmap2[k])
 			return 0;
diff -Nru a/lib/inflate.c b/lib/inflate.c
--- a/lib/inflate.c	Sat Apr  3 19:38:43 2004
+++ b/lib/inflate.c	Sat Apr  3 19:38:43 2004
@@ -102,6 +102,7 @@
       a repeat code (16, 17, or 18) to go across the boundary between
       the two sets of lengths.
  */
+#include <linux/compiler.h>
 
 #ifdef RCSID
 static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
@@ -685,8 +686,10 @@
 }
 
 
-
-STATIC int inflate_fixed(void)
+/*
+ * We use `noinline' here to prevent gcc-3.5 from using too much stack space
+ */
+STATIC int noinline inflate_fixed(void)
 /* decompress an inflated type 1 (fixed Huffman codes) block.  We should
    either replace this with a custom decoder, or at least precompute the
    Huffman tables. */
@@ -739,8 +742,10 @@
 }
 
 
-
-STATIC int inflate_dynamic(void)
+/*
+ * We use `noinline' here to prevent gcc-3.5 from using too much stack space
+ */
+STATIC int noinline inflate_dynamic(void)
 /* decompress an inflated type 2 (dynamic Huffman codes) block. */
 {
   int i;                /* temporary variables */
diff -Nru a/lib/kref.c b/lib/kref.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/lib/kref.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,60 @@
+/*
+ * kref.c - library routines for handling generic reference counted objects
+ *
+ * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2004 IBM Corp.
+ *
+ * based on lib/kobject.c which was:
+ * Copyright (C) 2002-2003 Patrick Mochel <mochel@osdl.org>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+/* #define DEBUG */
+
+#include <linux/kref.h>
+#include <linux/module.h>
+
+/**
+ * kref_init - initialize object.
+ * @kref: object in question.
+ * @release: pointer to a function that will clean up the object
+ *	     when the last reference to the object is released.
+ *	     This pointer is required.
+ */
+void kref_init(struct kref *kref, void (*release)(struct kref *kref))
+{
+	WARN_ON(release == NULL);
+	atomic_set(&kref->refcount,1);
+	kref->release = release;
+}
+
+/**
+ * kref_get - increment refcount for object.
+ * @kref: object.
+ */
+struct kref *kref_get(struct kref *kref)
+{
+	WARN_ON(!atomic_read(&kref->refcount));
+	atomic_inc(&kref->refcount);
+	return kref;
+}
+
+/**
+ * kref_put - decrement refcount for object.
+ * @kref: object.
+ *
+ * Decrement the refcount, and if 0, call kref->release().
+ */
+void kref_put(struct kref *kref)
+{
+	if (atomic_dec_and_test(&kref->refcount)) {
+		pr_debug("kref cleaning up\n");
+		kref->release(kref);
+	}
+}
+
+EXPORT_SYMBOL(kref_init);
+EXPORT_SYMBOL(kref_get);
+EXPORT_SYMBOL(kref_put);
diff -Nru a/lib/radix-tree.c b/lib/radix-tree.c
--- a/lib/radix-tree.c	Sat Apr  3 19:38:42 2004
+++ b/lib/radix-tree.c	Sat Apr  3 19:38:42 2004
@@ -24,6 +24,8 @@
 #include <linux/radix-tree.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
 #include <linux/gfp.h>
 #include <linux/string.h>
 
@@ -420,6 +422,28 @@
 		height_to_maxindex[i] = __maxindex(i);
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int radix_tree_callback(struct notifier_block *nfb,
+                            unsigned long action,
+                            void *hcpu)
+{
+       int cpu = (long)hcpu;
+       struct radix_tree_preload *rtp;
+
+       /* Free per-cpu pool of perloaded nodes */
+       if (action == CPU_DEAD) {
+               rtp = &per_cpu(radix_tree_preloads, cpu);
+               while (rtp->nr) {
+                       kmem_cache_free(radix_tree_node_cachep,
+                                       rtp->nodes[rtp->nr-1]);
+                       rtp->nodes[rtp->nr-1] = NULL;
+                       rtp->nr--;
+               }
+       }
+       return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 void __init radix_tree_init(void)
 {
 	radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
@@ -428,4 +452,5 @@
 	if (!radix_tree_node_cachep)
 		panic ("Failed to create radix_tree_node cache\n");
 	radix_tree_init_maxindex();
+	hotcpu_notifier(radix_tree_callback, 0);
 }
diff -Nru a/lib/zlib_deflate/deftree.c b/lib/zlib_deflate/deftree.c
--- a/lib/zlib_deflate/deftree.c	Sat Apr  3 19:38:42 2004
+++ b/lib/zlib_deflate/deftree.c	Sat Apr  3 19:38:42 2004
@@ -217,10 +217,6 @@
 }
 #endif /* DEBUG_ZLIB */
 
-
-#define MAX(a,b) (a >= b ? a : b)
-/* the arguments must not have side effects */
-
 /* ===========================================================================
  * Initialize the various 'constant' tables. In a multi-threaded environment,
  * this function may be called by two threads concurrently, but this is
@@ -598,7 +594,7 @@
 
         /* Create a new node father of n and m */
         tree[node].Freq = tree[n].Freq + tree[m].Freq;
-        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        s->depth[node] = (uch) (max(s->depth[n], s->depth[m]) + 1);
         tree[n].Dad = tree[m].Dad = (ush)node;
 #ifdef DUMP_BL_TREE
         if (tree == s->bl_tree) {
diff -Nru a/mm/fadvise.c b/mm/fadvise.c
--- a/mm/fadvise.c	Sat Apr  3 19:38:43 2004
+++ b/mm/fadvise.c	Sat Apr  3 19:38:43 2004
@@ -65,9 +65,8 @@
 	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 -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Sat Apr  3 19:38:42 2004
+++ b/mm/filemap.c	Sat Apr  3 19:38:42 2004
@@ -574,7 +574,7 @@
 
 /*
  * 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
@@ -725,7 +725,7 @@
 	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
 	if (cached_page)
 		page_cache_release(cached_page);
-	update_atime(inode);
+	file_accessed(filp);
 }
 
 EXPORT_SYMBOL(do_generic_mapping_read);
@@ -820,7 +820,7 @@
 			if (retval > 0)
 				*ppos = pos + retval;
 		}
-		update_atime(filp->f_dentry->d_inode);
+		file_accessed(filp);
 		goto out;
 	}
 
@@ -1353,11 +1353,10 @@
 int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
 {
 	struct address_space *mapping = file->f_mapping;
-	struct inode *inode = mapping->host;
 
 	if (!mapping->a_ops->readpage)
 		return -ENOEXEC;
-	update_atime(inode);
+	file_accessed(file);
 	vma->vm_ops = &generic_file_vm_ops;
 	return 0;
 }
@@ -1503,10 +1502,11 @@
  *	if suid or (sgid and xgrp)
  *		remove privs
  */
-void remove_suid(struct dentry *dentry)
+int remove_suid(struct dentry *dentry)
 {
 	mode_t mode = dentry->d_inode->i_mode;
 	int kill = 0;
+	int result = 0;
 
 	/* suid always must be killed */
 	if (unlikely(mode & S_ISUID))
@@ -1523,8 +1523,9 @@
 		struct iattr newattrs;
 
 		newattrs.ia_valid = ATTR_FORCE | kill;
-		notify_change(dentry, &newattrs);
+		result = notify_change(dentry, &newattrs);
 	}
+	return result;
 }
 EXPORT_SYMBOL(remove_suid);
 
@@ -1778,11 +1779,13 @@
 	if (err)
 		goto out;
 
-
 	if (count == 0)
 		goto out;
 
-	remove_suid(file->f_dentry);
+	err = remove_suid(file->f_dentry);
+	if (err)
+		goto out;
+
 	inode_update_time(inode, 1);
 
 	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Sat Apr  3 19:38:43 2004
+++ b/mm/memory.c	Sat Apr  3 19:38:43 2004
@@ -222,7 +222,7 @@
 	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);
@@ -335,7 +335,7 @@
 							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;
 
@@ -1336,7 +1336,7 @@
 	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);
diff -Nru a/mm/mempool.c b/mm/mempool.c
--- a/mm/mempool.c	Sat Apr  3 19:38:44 2004
+++ b/mm/mempool.c	Sat Apr  3 19:38:44 2004
@@ -209,6 +209,7 @@
 	 * 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);
@@ -236,6 +237,7 @@
 	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 +258,7 @@
 {
 	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 -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Sat Apr  3 19:38:44 2004
+++ b/mm/mmap.c	Sat Apr  3 19:38:44 2004
@@ -54,10 +54,12 @@
 
 int sysctl_overcommit_memory = 0;	/* default is heuristic overcommit */
 int sysctl_overcommit_ratio = 50;	/* default is 50% */
+int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT;
 atomic_t vm_committed_space = ATOMIC_INIT(0);
 
 EXPORT_SYMBOL(sysctl_overcommit_memory);
 EXPORT_SYMBOL(sysctl_overcommit_ratio);
+EXPORT_SYMBOL(sysctl_max_map_count);
 EXPORT_SYMBOL(vm_committed_space);
 
 /*
@@ -138,17 +140,34 @@
 }
 
 #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 +177,7 @@
 	}
 	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)
@@ -472,9 +491,13 @@
 	int correct_wcount = 0;
 	int error;
 	struct rb_node ** rb_link, * rb_parent;
+	int accountable = 1;
 	unsigned long charged = 0;
 
 	if (file) {
+		if (is_file_hugepages(file))
+			accountable = 0;
+
 		if (!file->f_op || !file->f_op->mmap)
 			return -ENODEV;
 
@@ -495,7 +518,7 @@
 		return -EINVAL;
 
 	/* Too many mappings? */
-	if (mm->map_count > MAX_MAP_COUNT)
+	if (mm->map_count > sysctl_max_map_count)
 		return -ENOMEM;
 
 	/* Obtain the address to map to. we verify (or select) it and ensure
@@ -591,7 +614,8 @@
 	    > current->rlim[RLIMIT_AS].rlim_cur)
 		return -ENOMEM;
 
-	if (!(flags & MAP_NORESERVE) || sysctl_overcommit_memory > 1) {
+	if (accountable && (!(flags & MAP_NORESERVE) ||
+			sysctl_overcommit_memory > 1)) {
 		if (vm_flags & VM_SHARED) {
 			/* Check memory availability in shmem_file_setup? */
 			vm_flags |= VM_ACCOUNT;
@@ -790,9 +814,10 @@
 			return -EINVAL;
 		if (file && is_file_hugepages(file))  {
 			/*
-			 * Make sure that addr and length are properly aligned.
+			 * Check if the given range is hugepage aligned, and
+			 * can be made suitable for hugepages.
 			 */
-			ret = is_aligned_hugepage_range(addr, len);
+			ret = prepare_hugepage_range(addr, len);
 		} else {
 			/*
 			 * Ensure that a normal request is not falling in a
@@ -1180,7 +1205,7 @@
 	struct vm_area_struct *new;
 	struct address_space *mapping = NULL;
 
-	if (mm->map_count >= MAX_MAP_COUNT)
+	if (mm->map_count >= sysctl_max_map_count)
 		return -ENOMEM;
 
 	new = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
@@ -1358,7 +1383,7 @@
 	    > current->rlim[RLIMIT_AS].rlim_cur)
 		return -ENOMEM;
 
-	if (mm->map_count > MAX_MAP_COUNT)
+	if (mm->map_count > sysctl_max_map_count)
 		return -ENOMEM;
 
 	if (security_vm_enough_memory(len >> PAGE_SHIFT))
diff -Nru a/mm/mprotect.c b/mm/mprotect.c
--- a/mm/mprotect.c	Sat Apr  3 19:38:57 2004
+++ b/mm/mprotect.c	Sat Apr  3 19:38:57 2004
@@ -173,7 +173,8 @@
 	 * a MAP_NORESERVE private mapping to writable will now reserve.
 	 */
 	if (newflags & VM_WRITE) {
-		if (!(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) {
+		if (!(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))
+				&& VM_MAYACCT(vma)) {
 			charged = (end - start) >> PAGE_SHIFT;
 			if (security_vm_enough_memory(charged))
 				return -ENOMEM;
@@ -237,7 +238,7 @@
 	len = PAGE_ALIGN(len);
 	end = start + len;
 	if (end < start)
-		return -EINVAL;
+		return -ENOMEM;
 	if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM))
 		return -EINVAL;
 	if (end == start)
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Sat Apr  3 19:38:41 2004
+++ b/mm/page_alloc.c	Sat Apr  3 19:38:41 2004
@@ -73,7 +73,7 @@
 {
 	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",
-		page->flags, page->mapping,
+		(unsigned long)page->flags, page->mapping,
 		page_mapped(page), page_count(page));
 	printk("Backtrace:\n");
 	dump_stack();
@@ -518,7 +518,7 @@
 
 	if (page != NULL) {
 		BUG_ON(bad_range(zone, page));
-		mod_page_state(pgalloc, 1 << order);
+		mod_page_state_zone(zone, pgalloc, 1 << order);
 		prep_new_page(page, order);
 	}
 	return page;
@@ -690,6 +690,42 @@
 
 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 +733,10 @@
 {
 	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;
@@ -1004,13 +1044,16 @@
 		K(nr_free_highpages()));
 
 	printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu "
-		"unstable:%lu free:%u\n",
+		"unstable:%lu free:%u slab:%lu mapped:%lu pagetables:%lu\n",
 		active,
 		inactive,
 		ps.nr_dirty,
 		ps.nr_writeback,
 		ps.nr_unstable,
-		nr_free_pages());
+		nr_free_pages(),
+		ps.nr_slab,
+		ps.nr_mapped,
+		ps.nr_page_table_pages);
 
 	for_each_zone(zone) {
 		show_node(zone);
@@ -1021,6 +1064,7 @@
 			" high:%lukB"
 			" active:%lukB"
 			" inactive:%lukB"
+			" present:%lukB"
 			"\n",
 			zone->name,
 			K(zone->free_pages),
@@ -1028,7 +1072,8 @@
 			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 +1133,112 @@
 	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 +1275,8 @@
 	} 
 }
 
+#endif	/* CONFIG_NUMA */
+
 void __init build_all_zonelists(void)
 {
 	int i;
@@ -1298,7 +1451,8 @@
 				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 +1635,38 @@
 	"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",
 };
 
@@ -1550,9 +1719,29 @@
 
 #endif /* CONFIG_PROC_FS */
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int page_alloc_cpu_notify(struct notifier_block *self,
+				 unsigned long action, void *hcpu)
+{
+	int cpu = (unsigned long)hcpu;
+	long *count;
+
+	if (action == CPU_DEAD) {
+		/* Drain local pagecache count. */
+		count = &per_cpu(nr_pagecache_local, cpu);
+		atomic_add(*count, &nr_pagecache);
+		*count = 0;
+		local_irq_disable();
+		__drain_pages(cpu);
+		local_irq_enable();
+	}
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
 
 void __init page_alloc_init(void)
 {
+	hotcpu_notifier(page_alloc_cpu_notify, 0);
 }
 
 /*
diff -Nru a/mm/pdflush.c b/mm/pdflush.c
--- a/mm/pdflush.c	Sat Apr  3 19:38:57 2004
+++ b/mm/pdflush.c	Sat Apr  3 19:38:57 2004
@@ -172,6 +172,12 @@
 static int pdflush(void *dummy)
 {
 	struct pdflush_work my_work;
+
+	/*
+	 * pdflush can spend a lot of time doing encryption via dm-crypt.  We
+	 * don't want to do that at keventd's priority.
+	 */
+	set_user_nice(current, 0);
 	return __pdflush(&my_work);
 }
 
diff -Nru a/mm/readahead.c b/mm/readahead.c
--- a/mm/readahead.c	Sat Apr  3 19:38:41 2004
+++ b/mm/readahead.c	Sat Apr  3 19:38:41 2004
@@ -30,6 +30,7 @@
 {
 	memset(ra, 0, sizeof(*ra));
 	ra->ra_pages = mapping->backing_dev_info->ra_pages;
+	ra->average = ra->ra_pages / 2;
 }
 
 EXPORT_SYMBOL(file_ra_state_init);
@@ -380,9 +381,18 @@
 		 */
 		first_access=1;
 		ra->next_size = max / 2;
+		ra->prev_page = offset;
+		ra->serial_cnt++;
 		goto do_io;
 	}
 
+	if (offset == ra->prev_page + 1) {
+		if (ra->serial_cnt <= (max * 2))
+			ra->serial_cnt++;
+	} else {
+		ra->average = (ra->average + ra->serial_cnt) / 2;
+		ra->serial_cnt = 1;
+	}
 	preoffset = ra->prev_page;
 	ra->prev_page = offset;
 
@@ -449,8 +459,12 @@
 			  * accessed in the current window, there
 			  * is a high probability that around 'n' pages
 			  * shall be used in the next current window.
+			  *
+			  * To minimize lazy-readahead triggered
+			  * in the next current window, read in
+			  * an extra page.
 			  */
-			ra->next_size = preoffset - ra->start + 1;
+			ra->next_size = preoffset - ra->start + 2;
 		}
 		ra->start = offset;
 		ra->size = ra->next_size;
@@ -468,17 +482,34 @@
 		}
 	} 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 -Nru a/mm/rmap.c b/mm/rmap.c
--- a/mm/rmap.c	Sat Apr  3 19:38:55 2004
+++ b/mm/rmap.c	Sat Apr  3 19:38:55 2004
@@ -50,7 +50,8 @@
 
 /*
  * next_and_idx encodes both the address of the next pte_chain and the
- * offset of the highest-index used pte in ptes[].
+ * offset of the lowest-index used pte in ptes[] (which is equal also
+ * to the offset of the highest-index unused pte in ptes[], plus one).
  */
 struct pte_chain {
 	unsigned long next_and_idx;
@@ -118,7 +119,7 @@
 	int referenced = 0;
 
 	if (page_test_and_clear_young(page))
-		mark_page_accessed(page);
+		referenced++;
 
 	if (TestClearPageReferenced(page))
 		referenced++;
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Sat Apr  3 19:38:43 2004
+++ b/mm/shmem.c	Sat Apr  3 19:38:43 2004
@@ -1061,14 +1061,8 @@
 
 static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct vm_operations_struct *ops;
-	struct inode *inode = file->f_dentry->d_inode;
-
-	ops = &shmem_vm_ops;
-	if (!S_ISREG(inode->i_mode))
-		return -EACCES;
-	update_atime(inode);
-	vma->vm_ops = ops;
+	file_accessed(file);
+	vma->vm_ops = &shmem_vm_ops;
 	return 0;
 }
 
@@ -1199,7 +1193,10 @@
 		}
 	}
 
-	remove_suid(file->f_dentry);
+	err = remove_suid(file->f_dentry);
+	if (err)
+		goto out;
+
 	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 
 	do {
@@ -1363,7 +1360,7 @@
 	}
 
 	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
-	update_atime(inode);
+	file_accessed(filp);
 }
 
 static ssize_t shmem_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Sat Apr  3 19:38:54 2004
+++ b/mm/slab.c	Sat Apr  3 19:38:54 2004
@@ -445,8 +445,8 @@
 /*
  * 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
@@ -576,7 +576,7 @@
  * Add the CPU number into the expiry time to minimize the possibility of the
  * CPUs getting into lockstep and contending for the global cache chain lock.
  */
-static void start_cpu_timer(int cpu)
+static void __devinit start_cpu_timer(int cpu)
 {
 	struct timer_list *rt = &per_cpu(reap_timers, cpu);
 
@@ -589,12 +589,19 @@
 	}
 }
 
-/*
- * Note: if someone calls kmem_cache_alloc() on the new
- * cpu before the cpuup callback had a chance to allocate
- * the head arrays, it will oops.
- * Is CPU_ONLINE early enough?
- */
+#ifdef CONFIG_HOTPLUG_CPU
+static void stop_cpu_timer(int cpu)
+{
+	struct timer_list *rt = &per_cpu(reap_timers, cpu);
+
+	if (rt->function) {
+		del_timer_sync(rt);
+		WARN_ON(timer_pending(rt));
+		rt->function = NULL;
+	}
+}
+#endif
+
 static int __devinit cpuup_callback(struct notifier_block *nfb,
 				  unsigned long action,
 				  void *hcpu)
@@ -630,18 +637,28 @@
 	case CPU_ONLINE:
 		start_cpu_timer(cpu);
 		break;
+#ifdef CONFIG_HOTPLUG_CPU
+	case CPU_DEAD:
+		stop_cpu_timer(cpu);
+		/* fall thru */
 	case CPU_UP_CANCELED:
 		down(&cache_chain_sem);
 
 		list_for_each_entry(cachep, &cache_chain, next) {
 			struct array_cache *nc;
 
+			spin_lock_irq(&cachep->spinlock);
+			/* cpu is dead; no one can alloc from it. */
 			nc = cachep->array[cpu];
 			cachep->array[cpu] = NULL;
+			cachep->free_limit -= cachep->batchcount;
+			free_block(cachep, ac_entry(nc), nc->avail);
+			spin_unlock_irq(&cachep->spinlock);
 			kfree(nc);
 		}
 		up(&cache_chain_sem);
 		break;
+#endif
 	}
 	return NOTIFY_OK;
 bad:
@@ -914,7 +931,7 @@
 		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;
@@ -1262,6 +1279,9 @@
 	cachep->dtor = dtor;
 	cachep->name = name;
 
+	/* Don't let CPUs to come and go */
+	lock_cpu_hotplug();
+
 	if (g_cpucache_up == FULL) {
 		enable_cpucache(cachep);
 	} else {
@@ -1311,6 +1331,7 @@
 			if (!strcmp(pc->name,name)) { 
 				printk("kmem_cache_create: duplicate cache %s\n",name); 
 				up(&cache_chain_sem); 
+				unlock_cpu_hotplug();
 				BUG(); 
 			}	
 		}
@@ -1320,6 +1341,7 @@
 	/* cache setup completed, link it into the list */
 	list_add(&cachep->next, &cache_chain);
 	up(&cache_chain_sem);
+	unlock_cpu_hotplug();
 opps:
 	return cachep;
 }
@@ -1470,6 +1492,9 @@
 	if (!cachep || in_interrupt())
 		BUG();
 
+	/* Don't let CPUs to come and go */
+	lock_cpu_hotplug();
+
 	/* Find the cache in the chain of caches. */
 	down(&cache_chain_sem);
 	/*
@@ -1483,9 +1508,13 @@
 		down(&cache_chain_sem);
 		list_add(&cachep->next,&cache_chain);
 		up(&cache_chain_sem);
+		unlock_cpu_hotplug();
 		return 1;
 	}
 
+	/* no cpu_online check required here since we clear the percpu
+	 * array on cpu offline and set this to NULL.
+	 */
 	for (i = 0; i < NR_CPUS; i++)
 		kfree(cachep->array[i]);
 
@@ -1494,6 +1523,8 @@
 	cachep->lists.shared = NULL;
 	kmem_cache_free(&cache_cache, cachep);
 
+	unlock_cpu_hotplug();
+
 	return 0;
 }
 
@@ -2885,7 +2916,8 @@
 #endif
 
 	page = virt_to_page((void*)addr);
-	printk("struct page at %p, flags %lxh.\n", page, page->flags);
+	printk("struct page at %p, flags %08lx\n",
+			page, (unsigned long)page->flags);
 	if (PageSlab(page)) {
 		kmem_cache_t *c;
 		struct slab *s;
diff -Nru a/mm/swap.c b/mm/swap.c
--- a/mm/swap.c	Sat Apr  3 19:38:43 2004
+++ b/mm/swap.c	Sat Apr  3 19:38:43 2004
@@ -27,6 +27,9 @@
 #include <linux/module.h>
 #include <linux/percpu_counter.h>
 #include <linux/percpu.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
 
 /* How many pages do we try to swap or page in/out together? */
 int page_cluster;
@@ -381,7 +384,37 @@
 	preempt_enable();
 }
 EXPORT_SYMBOL(vm_acct_memory);
-#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void lru_drain_cache(unsigned int cpu)
+{
+	struct pagevec *pvec = &per_cpu(lru_add_pvecs, cpu);
+
+	/* CPU is dead, so no locking needed. */
+	if (pagevec_count(pvec))
+		__pagevec_lru_add(pvec);
+	pvec = &per_cpu(lru_add_active_pvecs, cpu);
+	if (pagevec_count(pvec))
+		__pagevec_lru_add_active(pvec);
+}
+
+/* Drop the CPU's cached committed space back into the central pool. */
+static int cpu_swap_callback(struct notifier_block *nfb,
+			     unsigned long action,
+			     void *hcpu)
+{
+	long *committed;
+
+	committed = &per_cpu(committed_space, (long)hcpu);
+	if (action == CPU_DEAD) {
+		atomic_add(*committed, &vm_committed_space);
+		*committed = 0;
+		lru_drain_cache((long)hcpu);
+	}
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+#endif /* CONFIG_SMP */
 
 #ifdef CONFIG_SMP
 void percpu_counter_mod(struct percpu_counter *fbc, long amount)
@@ -420,4 +453,5 @@
 	 * Right now other parts of the system means that we
 	 * _really_ don't want to cluster much more
 	 */
+	hotcpu_notifier(cpu_swap_callback, 0);
 }
diff -Nru a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c	Sat Apr  3 19:38:41 2004
+++ b/mm/swapfile.c	Sat Apr  3 19:38:41 2004
@@ -1167,7 +1167,7 @@
 
 	file = ptr->swap_file;
 	len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
-	seq_printf(swap, "%*s %s\t%d\t%ld\t%d\n",
+	seq_printf(swap, "%*s%s\t%d\t%ld\t%d\n",
 		       len < 40 ? 40 - len : 1, " ",
 		       S_ISBLK(file->f_dentry->d_inode->i_mode) ?
 				"partition" : "file\t",
@@ -1242,7 +1242,19 @@
 		if (!(p->flags & SWP_USED))
 			break;
 	error = -EPERM;
-	if (type >= MAX_SWAPFILES) {
+	/*
+	 * Test if adding another swap device is possible. There are
+	 * two limiting factors: 1) the number of bits for the swap
+	 * type swp_entry_t definition and 2) the number of bits for
+	 * the swap type in the swap ptes as defined by the different
+	 * architectures. To honor both limitations a swap entry
+	 * with swap offset 0 and swap type ~0UL is created, encoded
+	 * to a swap pte, decoded to a swp_entry_t again and finally
+	 * the swap type part is extracted. This will mask all bits
+	 * from the initial ~0UL that can't be encoded in either the
+	 * swp_entry_t or the architecture definition of a swap pte.
+	 */
+	if (type > swp_type(pte_to_swp_entry(swp_entry_to_pte(swp_entry(~0UL,0))))) {
 		swap_list_unlock();
 		goto out;
 	}
@@ -1269,8 +1281,10 @@
 	swap_list_unlock();
 	name = getname(specialfile);
 	error = PTR_ERR(name);
-	if (IS_ERR(name))
+	if (IS_ERR(name)) {
+		name = NULL;
 		goto bad_swap_2;
+	}
 	swap_file = filp_open(name, O_RDWR, 0);
 	error = PTR_ERR(swap_file);
 	if (IS_ERR(swap_file)) {
@@ -1362,7 +1376,21 @@
 		}
 
 		p->lowest_bit  = 1;
-		maxpages = swp_offset(swp_entry(0,~0UL)) - 1;
+		/*
+		 * Find out how many pages are allowed for a single swap
+		 * device. There are two limiting factors: 1) the number of
+		 * bits for the swap offset in the swp_entry_t type and
+		 * 2) the number of bits in the a swap pte as defined by
+		 * the different architectures. In order to find the
+		 * largest possible bit mask a swap entry with swap type 0
+		 * and swap offset ~0UL is created, encoded to a swap pte,
+		 * decoded to a swp_entry_t again and finally the swap
+		 * offset is extracted. This will mask all the bits from
+		 * the initial ~0UL mask that can't be encoded in either
+		 * the swp_entry_t or the architecture definition of a
+		 * swap pte.
+		 */
+		maxpages = swp_offset(pte_to_swp_entry(swp_entry_to_pte(swp_entry(0,~0UL)))) - 1;
 		if (maxpages > swap_header->info.last_page)
 			maxpages = swap_header->info.last_page;
 		p->highest_bit = maxpages - 1;
diff -Nru a/mm/truncate.c b/mm/truncate.c
--- a/mm/truncate.c	Sat Apr  3 19:38:56 2004
+++ b/mm/truncate.c	Sat Apr  3 19:38:56 2004
@@ -219,6 +219,8 @@
 			ret += invalidate_complete_page(mapping, page);
 unlock:
 			unlock_page(page);
+			if (next > end)
+				break;
 		}
 		pagevec_release(&pvec);
 		cond_resched();
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Sat Apr  3 19:38:41 2004
+++ b/mm/vmscan.c	Sat Apr  3 19:38:41 2004
@@ -30,6 +30,8 @@
 #include <linux/backing-dev.h>
 #include <linux/rmap-locking.h>
 #include <linux/topology.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
 
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
@@ -43,14 +45,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 +67,7 @@
 		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 +137,7 @@
  *
  * We do weird things to avoid (scanned*seeks*entries) overflowing 32 bits.
  */
-static int shrink_slab(long scanned, unsigned int gfp_mask)
+static int shrink_slab(unsigned long scanned, unsigned int gfp_mask)
 {
 	struct shrinker *shrinker;
 	long pages;
@@ -147,7 +149,7 @@
 	list_for_each_entry(shrinker, &shrinker_list, list) {
 		unsigned long long delta;
 
-		delta = 4 * (scanned / shrinker->seeks);
+		delta = (4 * scanned) / shrinker->seeks;
 		delta *= (*shrinker->shrinker)(0, gfp_mask);
 		do_div(delta, pages + 1);
 		shrinker->nr += delta;
@@ -155,6 +157,7 @@
 			long nr_to_scan = shrinker->nr;
 
 			shrinker->nr = 0;
+			mod_page_state(slabs_scanned, nr_to_scan);
 			while (nr_to_scan) {
 				long this_scan = nr_to_scan;
 
@@ -243,8 +246,7 @@
  * 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 +262,7 @@
 		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 +270,7 @@
 
 		/* Double the slab pressure for mapped and swapcache pages */
 		if (page_mapped(page) || PageSwapCache(page))
-			(*nr_mapped)++;
+			(*nr_scanned)++;
 
 		BUG_ON(PageActive(page));
 
@@ -459,9 +461,6 @@
 	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 +470,33 @@
  * 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 +522,16 @@
 			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 +541,7 @@
 		 * 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 +581,7 @@
  */
 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 +600,7 @@
 	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 +651,20 @@
 		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 +682,7 @@
 	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 +711,7 @@
 
 	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 +730,20 @@
 	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 +755,23 @@
 	 * 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 +792,13 @@
  */
 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 +807,8 @@
 		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 +835,6 @@
 {
 	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 +850,13 @@
 
 		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 +870,8 @@
 		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 +898,13 @@
  * 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 +923,80 @@
 
 	for (priority = DEF_PRIORITY; priority; priority--) {
 		int all_zones_ok = 1;
+		int pages_scanned = 0;
+		int end_zone = 0;	/* Inclusive.  0 = ZONE_DMA */
+
 
-		for (i = 0; i < pgdat->nr_zones; i++) {
+		if (nr_pages == 0) {
+			/*
+			 * Scan in the highmem->dma direction for the highest
+			 * zone which needs scanning
+			 */
+			for (i = pgdat->nr_zones - 1; i >= 0; i--) {
+				struct zone *zone = pgdat->node_zones + i;
+
+				if (zone->all_unreclaimable &&
+						priority != DEF_PRIORITY)
+					continue;
+
+				if (zone->free_pages <= zone->pages_high) {
+					end_zone = i;
+					goto scan;
+				}
+			}
+			goto out;
+		} else {
+			end_zone = pgdat->nr_zones - 1;
+		}
+scan:
+		/*
+		 * Now scan the zone in the dma->highmem direction, stopping
+		 * at the last zone which needs scanning.
+		 *
+		 * We do this because the page allocator works in the opposite
+		 * direction.  This prevents the page allocator from allocating
+		 * pages behind kswapd's direction of progress, which would
+		 * cause too much scanning of the lower zones.
+		 */
+		for (i = 0; i <= end_zone; i++) {
 			struct zone *zone = pgdat->node_zones + i;
-			int nr_mapped = 0;
+			int total_scanned = 0;
 			int max_scan;
-			int to_reclaim;
+			int reclaimed;
 
 			if (zone->all_unreclaimable && priority != DEF_PRIORITY)
 				continue;
 
-			if (nr_pages && to_free > 0) {	/* Software suspend */
-				to_reclaim = min(to_free, SWAP_CLUSTER_MAX*8);
-			} else {			/* Zone balancing */
-				to_reclaim = zone->pages_high-zone->free_pages;
-				if (to_reclaim <= 0)
-					continue;
+			if (nr_pages == 0) {	/* Not software suspend */
+				if (zone->free_pages <= zone->pages_high)
+					all_zones_ok = 0;
 			}
 			zone->temp_priority = priority;
-			all_zones_ok = 0;
 			max_scan = zone->nr_inactive >> priority;
-			if (max_scan < to_reclaim * 2)
-				max_scan = to_reclaim * 2;
-			if (max_scan < SWAP_CLUSTER_MAX)
-				max_scan = SWAP_CLUSTER_MAX;
-			to_free -= shrink_zone(zone, max_scan, GFP_KERNEL,
-					to_reclaim, &nr_mapped, ps, priority);
-			if (i < ZONE_HIGHMEM) {
-				reclaim_state->reclaimed_slab = 0;
-				shrink_slab(max_scan + nr_mapped, GFP_KERNEL);
-				to_free -= reclaim_state->reclaimed_slab;
-			}
+			reclaimed = shrink_zone(zone, max_scan, GFP_KERNEL,
+					&total_scanned, ps);
+			total_scanned += pages_scanned;
+			reclaim_state->reclaimed_slab = 0;
+			shrink_slab(total_scanned, GFP_KERNEL);
+			reclaimed += reclaim_state->reclaimed_slab;
+			to_free -= reclaimed;
 			if (zone->all_unreclaimable)
 				continue;
 			if (zone->pages_scanned > zone->present_pages * 2)
 				zone->all_unreclaimable = 1;
 		}
+		if (nr_pages && to_free > 0)
+			continue;	/* swsusp: need to do more work */
 		if (all_zones_ok)
-			break;
-		if (to_free > 0)
+			break;		/* kswapd: all done */
+		/*
+		 * OK, kswapd is getting into trouble.  Take a nap, then take
+		 * another pass across the zones.
+		 */
+		if (pages_scanned && priority < DEF_PRIORITY - 2)
 			blk_congestion_wait(WRITE, HZ/10);
 	}
-
+out:
 	for (i = 0; i < pgdat->nr_zones; i++) {
 		struct zone *zone = pgdat->node_zones + i;
 
@@ -1085,13 +1104,39 @@
 }
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+/* It's optimal to keep kswapds on the same CPUs as their memory, but
+   not required for correctness.  So if the last cpu in a node goes
+   away, we get changed to run anywhere: as the first one comes back,
+   restore their cpu bindings. */
+static int __devinit cpu_callback(struct notifier_block *nfb,
+				  unsigned long action,
+				  void *hcpu)
+{
+	pg_data_t *pgdat;
+	cpumask_t mask;
+
+	if (action == CPU_ONLINE) {
+		for_each_pgdat(pgdat) {
+			mask = node_to_cpumask(pgdat->node_id);
+			if (any_online_cpu(mask) != NR_CPUS)
+				/* One of our CPUs online: restore mask */
+				set_cpus_allowed(pgdat->kswapd, mask);
+		}
+	}
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init kswapd_init(void)
 {
 	pg_data_t *pgdat;
 	swap_setup();
 	for_each_pgdat(pgdat)
-		kernel_thread(kswapd, pgdat, CLONE_KERNEL);
+		pgdat->kswapd
+		= find_task_by_pid(kernel_thread(kswapd, pgdat, CLONE_KERNEL));
 	total_memory = nr_free_pagecache_pages();
+	hotcpu_notifier(cpu_callback, 0);
 	return 0;
 }
 
diff -Nru a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
--- a/net/8021q/vlanproc.c	Sat Apr  3 19:38:42 2004
+++ b/net/8021q/vlanproc.c	Sat Apr  3 19:38:42 2004
@@ -305,7 +305,7 @@
 	struct net_device *vlandev = (struct net_device *) seq->private;
 	const struct vlan_dev_info *dev_info = VLAN_DEV_INFO(vlandev);
 	struct net_device_stats *stats;
-	static const char *fmt = "%30s %12lu\n";
+	static const char fmt[] = "%30s %12lu\n";
 	int i;
 
 	if ((vlandev == NULL) || (!(vlandev->priv_flags & IFF_802_1Q_VLAN)))
diff -Nru a/net/Kconfig b/net/Kconfig
--- a/net/Kconfig	Sat Apr  3 19:38:41 2004
+++ b/net/Kconfig	Sat Apr  3 19:38:41 2004
@@ -658,4 +658,20 @@
 
 source "net/bluetooth/Kconfig"
 
+config NETPOLL
+	def_bool NETCONSOLE
+
+config NETPOLL_RX
+	bool "Netpoll support for trapping incoming packets"
+	default n
+	depends on NETPOLL
+
+config NETPOLL_TRAP
+	bool "Netpoll traffic trapping"
+	default n
+	depends on NETPOLL
+
+config NET_POLL_CONTROLLER
+	def_bool NETPOLL
+
 endmenu
diff -Nru a/net/Makefile b/net/Makefile
--- a/net/Makefile	Sat Apr  3 19:38:43 2004
+++ b/net/Makefile	Sat Apr  3 19:38:43 2004
@@ -16,7 +16,9 @@
 obj-$(CONFIG_NET)		+= ethernet/ 802/ sched/ netlink/
 obj-$(CONFIG_INET)		+= ipv4/ xfrm/
 obj-$(CONFIG_UNIX)		+= unix/
-obj-$(CONFIG_IPV6)		+= ipv6/
+ifneq ($(CONFIG_IPV6),)
+obj-y				+= ipv6/
+endif
 obj-$(CONFIG_PACKET)		+= packet/
 obj-$(CONFIG_NET_KEY)		+= key/
 obj-$(CONFIG_NET_SCHED)		+= sched/
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Sat Apr  3 19:38:44 2004
+++ b/net/atm/lec.c	Sat Apr  3 19:38:44 2004
@@ -797,8 +797,8 @@
 	vcc->pop = lec_pop;
         lec_vcc_added(dev_lec[ioc_data.dev_num]->priv, 
                       &ioc_data, vcc, vcc->push);
-        vcc->push = lec_push;
         vcc->proto_data = dev_lec[ioc_data.dev_num];
+        vcc->push = lec_push;
         return 0;
 }
 
diff -Nru a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
--- a/net/atm/mpoa_proc.c	Sat Apr  3 19:38:55 2004
+++ b/net/atm/mpoa_proc.c	Sat Apr  3 19:38:55 2004
@@ -103,7 +103,7 @@
 			     size_t count, loff_t *pos){
         unsigned long page = 0;
 	unsigned char *temp;
-        ssize_t length  = 0;
+        int length = 0;
 	int i = 0;
 	struct mpoa_client *mpc = mpcs;
 	in_cache_entry *in_entry;
diff -Nru a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
--- a/net/bluetooth/af_bluetooth.c	Sat Apr  3 19:38:41 2004
+++ b/net/bluetooth/af_bluetooth.c	Sat Apr  3 19:38:41 2004
@@ -323,7 +323,7 @@
 	return err;
 }
 
-struct net_proto_family bt_sock_family_ops = {
+static struct net_proto_family bt_sock_family_ops = {
 	.owner  = THIS_MODULE,
 	.family	= PF_BLUETOOTH,
 	.create	= bt_sock_create,
@@ -364,7 +364,7 @@
 	return 0;
 }
 
-static void __exit bt_cleanup(void)
+static void __exit bt_exit(void)
 {
 	hci_sock_cleanup();
 
@@ -377,9 +377,10 @@
 }
 
 subsys_initcall(bt_init);
-module_exit(bt_cleanup);
+module_exit(bt_exit);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth Core ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_NETPROTO(PF_BLUETOOTH);
diff -Nru a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
--- a/net/bluetooth/bnep/core.c	Sat Apr  3 19:38:45 2004
+++ b/net/bluetooth/bnep/core.c	Sat Apr  3 19:38:45 2004
@@ -5,7 +5,7 @@
 	Clément Moreau <clement.moreau@inventel.fr>
 	David Libault  <david.libault@inventel.fr>
 
-   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
 
    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
@@ -672,7 +672,7 @@
 	return err;
 }
 
-static int  __init bnep_init_module(void)
+static int __init bnep_init(void)
 {	
 	char flt[50] = "";
 
@@ -694,15 +694,16 @@
 	return 0;
 }
 
-static void __exit bnep_cleanup_module(void)
+static void __exit bnep_exit(void)
 {
 	bnep_sock_cleanup();
 }
 
-module_init(bnep_init_module);
-module_exit(bnep_cleanup_module);
+module_init(bnep_init);
+module_exit(bnep_exit);
 
+MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
-MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("bt-proto-4");
diff -Nru a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c
--- a/net/bluetooth/bnep/netdev.c	Sat Apr  3 19:38:54 2004
+++ b/net/bluetooth/bnep/netdev.c	Sat Apr  3 19:38:54 2004
@@ -5,7 +5,7 @@
 	Clément Moreau <clement.moreau@inventel.fr>
 	David Libault  <david.libault@inventel.fr>
 
-   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
 
    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
diff -Nru a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
--- a/net/bluetooth/bnep/sock.c	Sat Apr  3 19:38:57 2004
+++ b/net/bluetooth/bnep/sock.c	Sat Apr  3 19:38:57 2004
@@ -4,7 +4,7 @@
    Written 2001-2002 by
 	David Libault  <david.libault@inventel.fr>
 
-   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
+   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
 
    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
diff -Nru a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
--- a/net/bluetooth/cmtp/core.c	Sat Apr  3 19:38:55 2004
+++ b/net/bluetooth/cmtp/core.c	Sat Apr  3 19:38:55 2004
@@ -482,7 +482,7 @@
 }
 
 
-int __init init_cmtp(void)
+static int __init cmtp_init(void)
 {
 	l2cap_load();
 
@@ -493,15 +493,16 @@
 	return 0;
 }
 
-void __exit exit_cmtp(void)
+static void __exit cmtp_exit(void)
 {
 	cmtp_cleanup_sockets();
 }
 
-module_init(init_cmtp);
-module_exit(exit_cmtp);
+module_init(cmtp_init);
+module_exit(cmtp_exit);
 
 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth CMTP ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("bt-proto-5");
diff -Nru a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
--- a/net/bluetooth/hci_event.c	Sat Apr  3 19:38:40 2004
+++ b/net/bluetooth/hci_event.c	Sat Apr  3 19:38:40 2004
@@ -222,7 +222,7 @@
 		vs = (struct hci_rp_read_voice_setting *) skb->data;
 
 		if (vs->status) {
-			BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vc->status);
+			BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vs->status);
 			break;
 		}
 
@@ -359,7 +359,7 @@
 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
 
 	BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name,
-			status, batostr(&cc->bdaddr), conn);
+			status, batostr(&cp->bdaddr), conn);
 
 	if (status) {
 		if (conn) {
diff -Nru a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
--- a/net/bluetooth/hci_sysfs.c	Sat Apr  3 19:38:54 2004
+++ b/net/bluetooth/hci_sysfs.c	Sat Apr  3 19:38:54 2004
@@ -52,7 +52,7 @@
 		n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x 0x%.2x %u\n",
 				batostr(&bdaddr),
 				info->pscan_rep_mode, info->pscan_period_mode, info->pscan_mode,
-				info->dev_class[0], info->dev_class[1], info->dev_class[2],
+				info->dev_class[2], info->dev_class[1], info->dev_class[0],
 				info->clock_offset, 0, e->timestamp);
 	}
 
diff -Nru a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
--- a/net/bluetooth/l2cap.c	Sat Apr  3 19:38:45 2004
+++ b/net/bluetooth/l2cap.c	Sat Apr  3 19:38:45 2004
@@ -535,7 +535,7 @@
 	return err;
 }
 
-int l2cap_sock_listen(struct socket *sock, int backlog)
+static int l2cap_sock_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
 	int err = 0;
@@ -563,7 +563,7 @@
 	return err;
 }
 
-int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct sock *sk = sock->sk, *nsk;
@@ -1051,7 +1051,7 @@
 }
 
 /* Copy frame to all raw sockets on that connection */
-void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct l2cap_chan_list *l = &conn->chan_list;
 	struct sk_buff *nskb;
@@ -2153,7 +2153,7 @@
 	.recv_acldata =	l2cap_recv_acldata
 };
 
-int __init l2cap_init(void)
+static int __init l2cap_init(void)
 {
 	int err;
 
@@ -2175,7 +2175,7 @@
 	return 0;
 }
 
-void __exit l2cap_cleanup(void)
+static void __exit l2cap_exit(void)
 {
 	l2cap_proc_cleanup();
 
@@ -2197,9 +2197,10 @@
 EXPORT_SYMBOL(l2cap_load);
 
 module_init(l2cap_init);
-module_exit(l2cap_cleanup);
+module_exit(l2cap_exit);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("Bluetooth L2CAP ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("bt-proto-0");
diff -Nru a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
--- a/net/bluetooth/rfcomm/core.c	Sat Apr  3 19:38:40 2004
+++ b/net/bluetooth/rfcomm/core.c	Sat Apr  3 19:38:40 2004
@@ -1948,7 +1948,7 @@
 #endif /* CONFIG_PROC_FS */
 
 /* ---- Initialization ---- */
-int  __init rfcomm_init(void)
+static int __init rfcomm_init(void)
 {
 	l2cap_load();
 
@@ -1967,7 +1967,7 @@
 	return 0;
 }
 
-void __exit rfcomm_cleanup(void)
+static void __exit rfcomm_exit(void)
 {
 	/* Terminate working thread.
 	 * ie. Set terminate flag and wake it up */
@@ -1988,9 +1988,10 @@
 }
 
 module_init(rfcomm_init);
-module_exit(rfcomm_cleanup);
+module_exit(rfcomm_exit);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
 MODULE_DESCRIPTION("Bluetooth RFCOMM ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("bt-proto-3");
diff -Nru a/net/bluetooth/sco.c b/net/bluetooth/sco.c
--- a/net/bluetooth/sco.c	Sat Apr  3 19:38:42 2004
+++ b/net/bluetooth/sco.c	Sat Apr  3 19:38:42 2004
@@ -194,7 +194,7 @@
 	return err;
 }
 
-int sco_connect(struct sock *sk)
+static int sco_connect(struct sock *sk)
 {
 	bdaddr_t *src = &bt_sk(sk)->src;
 	bdaddr_t *dst = &bt_sk(sk)->dst;
@@ -533,7 +533,7 @@
 	return err;
 }
 
-int sco_sock_listen(struct socket *sock, int backlog)
+static int sco_sock_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
 	int err = 0;
@@ -556,7 +556,7 @@
 	return err;
 }
 
-int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct sock *sk = sock->sk, *ch;
@@ -655,7 +655,7 @@
 	return err;
 }
 
-int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
 	int err = 0;
@@ -674,7 +674,7 @@
 	return err;
 }
 
-int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
 {
 	struct sock *sk = sock->sk;
 	struct sco_options opts;
@@ -835,7 +835,7 @@
 }
 
 /* ----- SCO interface with lower layer (HCI) ----- */
-int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
+static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
 {
 	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
 
@@ -843,7 +843,7 @@
 	return HCI_LM_ACCEPT;
 }
 
-int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
 {
 	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 
@@ -862,7 +862,7 @@
 	return 0;
 }
 
-int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
+static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
 {
 	BT_DBG("hcon %p reason %d", hcon, reason);
 
@@ -873,7 +873,7 @@
 	return 0;
 }
 
-int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
+static int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
 {
 	struct sco_conn *conn = hcon->sco_data;
 
@@ -1013,7 +1013,7 @@
 	.recv_scodata =	sco_recv_scodata
 };
 
-int __init sco_init(void)
+static int __init sco_init(void)
 {
 	int err;
 
@@ -1035,7 +1035,7 @@
 	return 0;
 }
 
-void __exit sco_cleanup(void)
+static void __exit sco_exit(void)
 {
 	int err;
 
@@ -1050,9 +1050,10 @@
 }
 
 module_init(sco_init);
-module_exit(sco_cleanup);
+module_exit(sco_exit);
 
 MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
 MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION);
+MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("bt-proto-2");
diff -Nru a/net/core/Makefile b/net/core/Makefile
--- a/net/core/Makefile	Sat Apr  3 19:38:55 2004
+++ b/net/core/Makefile	Sat Apr  3 19:38:55 2004
@@ -13,3 +13,4 @@
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 obj-$(CONFIG_NET_RADIO) += wireless.o
+obj-$(CONFIG_NETPOLL) += netpoll.o
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Sat Apr  3 19:38:43 2004
+++ b/net/core/dev.c	Sat Apr  3 19:38:43 2004
@@ -76,6 +76,7 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <linux/config.h>
+#include <linux/cpu.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -105,6 +106,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>
@@ -1538,6 +1540,13 @@
 	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 +1702,13 @@
 	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);
 
@@ -1820,7 +1836,6 @@
 	int budget = netdev_max_backlog;
 
 	
-	preempt_disable();
 	local_irq_disable();
 
 	while (!list_empty(&queue->poll_list)) {
@@ -1849,7 +1864,6 @@
 	}
 out:
 	local_irq_enable();
-	preempt_enable();
 	return;
 
 softnet_break:
@@ -3116,6 +3130,52 @@
 	return 0;
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int dev_cpu_callback(struct notifier_block *nfb,
+			    unsigned long action,
+			    void *ocpu)
+{
+	struct sk_buff **list_skb;
+	struct net_device **list_net;
+	struct sk_buff *skb;
+	unsigned int cpu, oldcpu = (unsigned long)ocpu;
+	struct softnet_data *sd, *oldsd;
+
+	if (action != CPU_DEAD)
+		return NOTIFY_OK;
+
+	local_irq_disable();
+	cpu = smp_processor_id();
+	sd = &per_cpu(softnet_data, cpu);
+	oldsd = &per_cpu(softnet_data, oldcpu);
+
+	/* Find end of our completion_queue. */
+	list_skb = &sd->completion_queue;
+	while (*list_skb)
+		list_skb = &(*list_skb)->next;
+	/* Append completion queue from offline CPU. */
+	*list_skb = oldsd->completion_queue;
+	oldsd->completion_queue = NULL;
+
+	/* Find end of our output_queue. */
+	list_net = &sd->output_queue;
+	while (*list_net)
+		list_net = &(*list_net)->next_sched;
+	/* Append output queue from offline CPU. */
+	*list_net = oldsd->output_queue;
+	oldsd->output_queue = NULL;
+
+	raise_softirq_irqoff(NET_TX_SOFTIRQ);
+	local_irq_enable();
+
+	/* Process offline CPU's input_pkt_queue */
+	while ((skb = __skb_dequeue(&oldsd->input_pkt_queue)))
+		netif_rx(skb);
+
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 
 /*
  *	Initialize the DEV module. At boot time this walks the device list and
@@ -3180,6 +3240,7 @@
 	open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
 	open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);
 
+	hotcpu_notifier(dev_cpu_callback, 0);
 	dst_init();
 	dev_mcast_init();
 	rc = 0;
diff -Nru a/net/core/flow.c b/net/core/flow.c
--- a/net/core/flow.c	Sat Apr  3 19:38:41 2004
+++ b/net/core/flow.c	Sat Apr  3 19:38:41 2004
@@ -326,6 +326,17 @@
 	tasklet_init(tasklet, flow_cache_flush_tasklet, 0);
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int flow_cache_cpu(struct notifier_block *nfb,
+			  unsigned long action,
+			  void *hcpu)
+{
+	if (action == CPU_DEAD)
+		__flow_cache_shrink((unsigned long)hcpu, 0);
+	return NOTIFY_OK;
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
 static int __init flow_cache_init(void)
 {
 	int i;
@@ -350,6 +361,7 @@
 	for_each_cpu(i)
 		flow_cache_cpu_prepare(i);
 
+	hotcpu_notifier(flow_cache_cpu, 0);
 	return 0;
 }
 
diff -Nru a/net/core/netpoll.c b/net/core/netpoll.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/core/netpoll.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/net/decnet/README b/net/decnet/README
--- a/net/decnet/README	Sat Apr  3 19:38:43 2004
+++ b/net/decnet/README	Sat Apr  3 19:38:43 2004
@@ -2,7 +2,7 @@
                       ======================
 
 The documentation for this kernel subsystem is available in the
-Documentation/networking subdirctory of this distribution and also
+Documentation/networking subdirectory of this distribution and also
 on line at http://www.chygwyn.com/DECnet/
 
 Steve Whitehouse <SteveW@ACM.org>
diff -Nru a/net/ipv4/Kconfig b/net/ipv4/Kconfig
--- a/net/ipv4/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/net/ipv4/Kconfig	Sat Apr  3 19:38:54 2004
@@ -287,25 +287,6 @@
 	  and you should also say Y to "Kernel/User network link driver",
 	  below. If unsure, say N.
 
-config INET_ECN
-	bool "IP: TCP Explicit Congestion Notification support"
-	depends on INET
-	---help---
-	  Explicit Congestion Notification (ECN) allows routers to notify
-	  clients about network congestion, resulting in fewer dropped packets
-	  and increased network performance.  This option adds ECN support to
-	  the Linux kernel, as well as a sysctl (/proc/sys/net/ipv4/tcp_ecn)
-	  which allows ECN support to be disabled at runtime.
-
-	  Note that, on the Internet, there are many broken firewalls which
-	  refuse connections from ECN-enabled machines, and it may be a while
-	  before these firewalls are fixed.  Until then, to access a site
-	  behind such a firewall (some of which are major sites, at the time
-	  of this writing) you will have to disable this option, either by
-	  saying N now or by using the sysctl.
-
-	  If in doubt, say N.
-
 config SYN_COOKIES
 	bool "IP: TCP syncookie support (disabled per default)"
 	depends on INET
diff -Nru a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c	Sat Apr  3 19:38:42 2004
+++ b/net/ipv4/devinet.c	Sat Apr  3 19:38:42 2004
@@ -165,6 +165,7 @@
 #ifdef CONFIG_SYSCTL
 	devinet_sysctl_register(in_dev, &in_dev->cnf);
 #endif
+	ip_mc_init_dev(in_dev);
 	if (dev->flags & IFF_UP)
 		ip_mc_up(in_dev);
 out:
diff -Nru a/net/ipv4/igmp.c b/net/ipv4/igmp.c
--- a/net/ipv4/igmp.c	Sat Apr  3 19:38:56 2004
+++ b/net/ipv4/igmp.c	Sat Apr  3 19:38:56 2004
@@ -1217,6 +1217,9 @@
 
 	ASSERT_RTNL();
 
+	for (i=in_dev->mc_list; i; i=i->next)
+		igmp_group_dropped(i);
+
 #ifdef CONFIG_IP_MULTICAST
 	in_dev->mr_ifc_count = 0;
 	if (del_timer(&in_dev->mr_ifc_timer))
@@ -1224,24 +1227,14 @@
 	in_dev->mr_gq_running = 0;
 	if (del_timer(&in_dev->mr_gq_timer))
 		__in_dev_put(in_dev);
-#endif
-
-	for (i=in_dev->mc_list; i; i=i->next)
-		igmp_group_dropped(i);
-
-#ifdef CONFIG_IP_MULTICAST
 	igmpv3_clear_delrec(in_dev);
 #endif
 
 	ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
 }
 
-/* Device going up */
-
-void ip_mc_up(struct in_device *in_dev)
+void ip_mc_init_dev(struct in_device *in_dev)
 {
-	struct ip_mc_list *i;
-
 	ASSERT_RTNL();
 
 	in_dev->mc_tomb = 0;
@@ -1258,6 +1251,16 @@
 #endif
 
 	in_dev->mc_lock = RW_LOCK_UNLOCKED;
+}
+
+/* Device going up */
+
+void ip_mc_up(struct in_device *in_dev)
+{
+	struct ip_mc_list *i;
+
+	ASSERT_RTNL();
+
 	ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
 
 	for (i=in_dev->mc_list; i; i=i->next)
diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c	Sat Apr  3 19:38:56 2004
+++ b/net/ipv4/ip_output.c	Sat Apr  3 19:38:56 2004
@@ -1187,6 +1187,10 @@
 
 out:
 	inet->cork.flags &= ~IPCORK_OPT;
+	if (inet->cork.opt) {
+		kfree(inet->cork.opt);
+		inet->cork.opt = NULL;
+	}
 	if (inet->cork.rt) {
 		ip_rt_put(inet->cork.rt);
 		inet->cork.rt = NULL;
diff -Nru a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
--- a/net/ipv4/ipconfig.c	Sat Apr  3 19:38:41 2004
+++ b/net/ipv4/ipconfig.c	Sat Apr  3 19:38:41 2004
@@ -1189,12 +1189,47 @@
 #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);
@@ -1282,6 +1317,10 @@
 		/* Device selected manually or only one device -> use it */
 		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 -Nru a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
--- a/net/ipv4/ipvs/Kconfig	Sat Apr  3 19:38:42 2004
+++ b/net/ipv4/ipvs/Kconfig	Sat Apr  3 19:38:42 2004
@@ -119,7 +119,7 @@
 	  module, choose M here. If unsure, say N.
 
 config	IP_VS_LC
-        tristate "least-connection scheduling scheduling"
+        tristate "least-connection scheduling"
         depends on IP_VS
 	---help---
 	  The least-connection scheduling algorithm directs network
diff -Nru a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
--- a/net/ipv4/ipvs/ip_vs_conn.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/ipvs/ip_vs_conn.c	Sat Apr  3 19:38:55 2004
@@ -125,25 +125,27 @@
 static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
 {
 	unsigned hash;
-
-	if (cp->flags & IP_VS_CONN_F_HASHED) {
-		IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, "
-			  "called from %p\n", __builtin_return_address(0));
-		return 0;
-	}
+	int ret;
 
 	/* Hash by protocol, client address and port */
 	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
 
 	ct_write_lock(hash);
 
-	list_add(&cp->c_list, &ip_vs_conn_tab[hash]);
-	cp->flags |= IP_VS_CONN_F_HASHED;
-	atomic_inc(&cp->refcnt);
+	if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
+		list_add(&cp->c_list, &ip_vs_conn_tab[hash]);
+		cp->flags |= IP_VS_CONN_F_HASHED;
+		atomic_inc(&cp->refcnt);
+		ret = 1;
+	} else {
+		IP_VS_ERR("ip_vs_conn_hash(): request for already hashed, "
+			  "called from %p\n", __builtin_return_address(0));
+		ret = 0;
+	}
 
 	ct_write_unlock(hash);
 
-	return 1;
+	return ret;
 }
 
 
@@ -154,24 +156,24 @@
 static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
 {
 	unsigned hash;
-
-	if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
-		IP_VS_ERR("ip_vs_conn_unhash(): request for unhash flagged, "
-			  "called from %p\n", __builtin_return_address(0));
-		return 0;
-	}
+	int ret;
 
 	/* unhash it and decrease its reference counter */
 	hash = ip_vs_conn_hashkey(cp->protocol, cp->caddr, cp->cport);
+
 	ct_write_lock(hash);
 
-	list_del(&cp->c_list);
-	cp->flags &= ~IP_VS_CONN_F_HASHED;
-	atomic_dec(&cp->refcnt);
+	if (cp->flags & IP_VS_CONN_F_HASHED) {
+		list_del(&cp->c_list);
+		cp->flags &= ~IP_VS_CONN_F_HASHED;
+		atomic_dec(&cp->refcnt);
+		ret = 1;
+	} else
+		ret = 0;
 
 	ct_write_unlock(hash);
 
-	return 1;
+	return ret;
 }
 
 
@@ -285,12 +287,18 @@
  */
 void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __u16 cport)
 {
-	atomic_dec(&ip_vs_conn_no_cport_cnt);
-	ip_vs_conn_unhash(cp);
-	cp->flags &= ~IP_VS_CONN_F_NO_CPORT;
-	cp->cport = cport;
-	/* hash on new dport */
-	ip_vs_conn_hash(cp);
+	if (ip_vs_conn_unhash(cp)) {
+		spin_lock(&cp->lock);
+		if (cp->flags & IP_VS_CONN_F_NO_CPORT) {
+			atomic_dec(&ip_vs_conn_no_cport_cnt);
+			cp->flags &= ~IP_VS_CONN_F_NO_CPORT;
+			cp->cport = cport;
+		}
+		spin_unlock(&cp->lock);
+
+		/* hash on new dport */
+		ip_vs_conn_hash(cp);
+	}
 }
 
 
@@ -457,11 +465,14 @@
 		/*
 		 * Invalidate the connection template
 		 */
-		ip_vs_conn_unhash(ct);
-		ct->dport = 65535;
-		ct->vport = 65535;
-		ct->cport = 0;
-		ip_vs_conn_hash(ct);
+		if (ct->cport) {
+			if (ip_vs_conn_unhash(ct)) {
+				ct->dport = 65535;
+				ct->vport = 65535;
+				ct->cport = 0;
+				ip_vs_conn_hash(ct);
+			}
+		}
 
 		/*
 		 * Simply decrease the refcnt of the template,
@@ -493,7 +504,8 @@
 	/*
 	 *	unhash it if it is hashed in the conn table
 	 */
-	ip_vs_conn_unhash(cp);
+	if (!ip_vs_conn_unhash(cp))
+		goto expire_later;
 
 	/*
 	 *	refcnt==1 implies I'm the only one referrer
diff -Nru a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
--- a/net/ipv4/ipvs/ip_vs_ctl.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/ipvs/ip_vs_ctl.c	Sat Apr  3 19:38:55 2004
@@ -898,9 +898,16 @@
 
 	__ip_vs_update_dest(svc, dest, udest);
 
+	write_lock_bh(&__ip_vs_svc_lock);
+
+	/* Wait until all other svc users go away */
+	while (atomic_read(&svc->usecnt) > 1) {};
+
 	/* call the update_service, because server weight may be changed */
 	svc->scheduler->update_service(svc);
 
+	write_unlock_bh(&__ip_vs_svc_lock);
+
 	LeaveFunction(2);
 
 	return 0;
@@ -1384,95 +1391,223 @@
 /*
  *	IPVS sysctl table (under the /proc/sys/net/ipv4/vs/)
  */
-struct ip_vs_sysctl_table {
-	struct ctl_table_header *sysctl_header;
-	ctl_table vs_vars[NET_IPV4_VS_LAST];
-	ctl_table vs_dir[2];
-	ctl_table ipv4_dir[2];
-	ctl_table root_dir[2];
-};
 
-static struct ip_vs_sysctl_table ipv4_vs_table = {
-	NULL,
-	{{NET_IPV4_VS_AMEMTHRESH, "amemthresh",
-	  &sysctl_ip_vs_amemthresh, sizeof(int), 0644, NULL,
-	  &proc_dointvec},
+static struct ctl_table vs_vars[] = {
+	{
+		.ctl_name	= NET_IPV4_VS_AMEMTHRESH,
+		.procname	= "amemthresh",
+		.data		= &sysctl_ip_vs_amemthresh,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 #ifdef CONFIG_IP_VS_DEBUG
-	 {NET_IPV4_VS_DEBUG_LEVEL, "debug_level",
-	  &sysctl_ip_vs_debug_level, sizeof(int), 0644, NULL,
-	  &proc_dointvec},
+	{
+		.ctl_name	= NET_IPV4_VS_DEBUG_LEVEL,
+		.procname	= "debug_level",
+		.data		= &sysctl_ip_vs_debug_level,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 #endif
-	 {NET_IPV4_VS_AMDROPRATE, "am_droprate",
-	  &sysctl_ip_vs_am_droprate, sizeof(int), 0644, NULL,
-	  &proc_dointvec},
-	 {NET_IPV4_VS_DROP_ENTRY, "drop_entry",
-	  &sysctl_ip_vs_drop_entry, sizeof(int), 0644, NULL,
-	  &proc_do_defense_mode},
-	 {NET_IPV4_VS_DROP_PACKET, "drop_packet",
-	  &sysctl_ip_vs_drop_packet, sizeof(int), 0644, NULL,
-	  &proc_do_defense_mode},
-	 {NET_IPV4_VS_SECURE_TCP, "secure_tcp",
-	  &sysctl_ip_vs_secure_tcp, sizeof(int), 0644, NULL,
-	  &proc_do_defense_mode},
+	{
+		.ctl_name	= NET_IPV4_VS_AMDROPRATE,
+		.procname	= "am_droprate",
+		.data		= &sysctl_ip_vs_am_droprate,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_DROP_ENTRY,
+		.procname	= "drop_entry",
+		.data		= &sysctl_ip_vs_drop_entry,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_do_defense_mode,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_DROP_PACKET,
+		.procname	= "drop_packet",
+		.data		= &sysctl_ip_vs_drop_packet,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_do_defense_mode,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_SECURE_TCP,
+		.procname	= "secure_tcp",
+		.data		= &sysctl_ip_vs_secure_tcp,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_do_defense_mode,
+	},
 #if 0
-	 {NET_IPV4_VS_TO_ES, "timeout_established",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_SS, "timeout_synsent",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_SR, "timeout_synrecv",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_FW, "timeout_finwait",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_TW, "timeout_timewait",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_CL, "timeout_close",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_CW, "timeout_closewait",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_LA, "timeout_lastack",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_LI, "timeout_listen",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_SA, "timeout_synack",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_UDP, "timeout_udp",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_UDP],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {NET_IPV4_VS_TO_ICMP, "timeout_icmp",
-	  &vs_timeout_table_dos.timeout[IP_VS_S_ICMP],
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_ES,
+		.procname	= "timeout_established",
+	  	.data	= &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_SS,
+		.procname	= "timeout_synsent",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_SR,
+		.procname	= "timeout_synrecv",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_FW,
+		.procname	= "timeout_finwait",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_TW,
+		.procname	= "timeout_timewait",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_CL,
+		.procname	= "timeout_close",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_CW,
+		.procname	= "timeout_closewait",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_LA,
+		.procname	= "timeout_lastack",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_LI,
+		.procname	= "timeout_listen",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_SA,
+		.procname	= "timeout_synack",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_UDP,
+		.procname	= "timeout_udp",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_UDP],
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_TO_ICMP,
+		.procname	= "timeout_icmp",
+		.data	= &vs_timeout_table_dos.timeout[IP_VS_S_ICMP],
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
 #endif
-	 {NET_IPV4_VS_CACHE_BYPASS, "cache_bypass",
-	  &sysctl_ip_vs_cache_bypass, sizeof(int), 0644, NULL,
-	  &proc_dointvec},
-	 {NET_IPV4_VS_EXPIRE_NODEST_CONN, "expire_nodest_conn",
-	  &sysctl_ip_vs_expire_nodest_conn, sizeof(int), 0644, NULL,
-	  &proc_dointvec},
-	 {NET_IPV4_VS_SYNC_THRESHOLD, "sync_threshold",
-	  &sysctl_ip_vs_sync_threshold, sizeof(sysctl_ip_vs_sync_threshold),
-	  0644, NULL, &proc_do_sync_threshold},
-	 {NET_IPV4_VS_NAT_ICMP_SEND, "nat_icmp_send",
-	  &sysctl_ip_vs_nat_icmp_send, sizeof(int), 0644, NULL,
-	  &proc_dointvec},
-	 {0}},
-	{{NET_IPV4_VS, "vs", NULL, 0, 0555, ipv4_vs_table.vs_vars},
-	 {0}},
-	{{NET_IPV4, "ipv4", NULL, 0, 0555, ipv4_vs_table.vs_dir},
-	 {0}},
-	{{CTL_NET, "net", NULL, 0, 0555, ipv4_vs_table.ipv4_dir},
-	 {0}}
+	{
+		.ctl_name	= NET_IPV4_VS_CACHE_BYPASS,
+		.procname	= "cache_bypass",
+		.data		= &sysctl_ip_vs_cache_bypass,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_EXPIRE_NODEST_CONN,
+		.procname	= "expire_nodest_conn",
+		.data		= &sysctl_ip_vs_expire_nodest_conn,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_SYNC_THRESHOLD,
+		.procname	= "sync_threshold",
+		.data		= &sysctl_ip_vs_sync_threshold,
+		.maxlen		= sizeof(sysctl_ip_vs_sync_threshold),
+		.mode		= 0644,
+		.proc_handler	= &proc_do_sync_threshold,
+	},
+	{
+		.ctl_name	= NET_IPV4_VS_NAT_ICMP_SEND,
+		.procname	= "nat_icmp_send",
+		.data		= &sysctl_ip_vs_nat_icmp_send,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{ .ctl_name = 0 }
 };
 
+static ctl_table vs_table[] = {
+	{
+		.ctl_name	= NET_IPV4_VS,
+		.procname	= "vs",
+		.mode		= 0555,
+		.child		= vs_vars
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table ipv4_table[] = {
+	{
+		.ctl_name	= NET_IPV4,
+		.procname	= "ipv4",
+		.mode		= 0555,
+		.child		= vs_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table vs_root_table[] = {
+	{
+		.ctl_name	= CTL_NET,
+		.procname	= "net",
+		.mode		= 0555,
+		.child		= ipv4_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static struct ctl_table_header * sysctl_header;
+
 #ifdef CONFIG_PROC_FS
 
 struct ip_vs_iter {
@@ -2184,9 +2319,13 @@
 
 
 static struct nf_sockopt_ops ip_vs_sockopts = {
-	{ NULL, NULL }, PF_INET,
-	IP_VS_BASE_CTL, IP_VS_SO_SET_MAX+1, do_ip_vs_set_ctl,
-	IP_VS_BASE_CTL, IP_VS_SO_GET_MAX+1, do_ip_vs_get_ctl
+	.pf		= PF_INET,
+	.set_optmin	= IP_VS_BASE_CTL,
+	.set_optmax	= IP_VS_SO_SET_MAX+1,
+	.set		= do_ip_vs_set_ctl,
+	.get_optmin	= IP_VS_BASE_CTL,
+	.get_optmax	= IP_VS_SO_GET_MAX+1,
+	.get		= do_ip_vs_get_ctl,
 };
 
 
@@ -2206,8 +2345,7 @@
 	proc_net_fops_create("ip_vs", 0, &ip_vs_info_fops);
 	proc_net_fops_create("ip_vs_stats",0, &ip_vs_stats_fops);
 
-	ipv4_vs_table.sysctl_header =
-		register_sysctl_table(ipv4_vs_table.root_dir, 0);
+	sysctl_header = register_sysctl_table(vs_root_table, 0);
 
 	/* Initialize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable */
 	for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++)  {
@@ -2239,7 +2377,7 @@
 	ip_vs_trash_cleanup();
 	del_timer_sync(&defense_timer);
 	ip_vs_kill_estimator(&ip_vs_stats);
-	unregister_sysctl_table(ipv4_vs_table.sysctl_header);
+	unregister_sysctl_table(sysctl_header);
 	proc_net_remove("ip_vs_stats");
 	proc_net_remove("ip_vs");
 	nf_unregister_sockopt(&ip_vs_sockopts);
diff -Nru a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
--- a/net/ipv4/ipvs/ip_vs_lblc.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/ipvs/ip_vs_lblc.c	Sat Apr  3 19:38:55 2004
@@ -108,29 +108,50 @@
 /*
  *      IPVS LBLC sysctl table
  */
-struct ip_vs_lblc_sysctl_table {
-	struct ctl_table_header *sysctl_header;
-	ctl_table vs_vars[2];
-	ctl_table vs_dir[2];
-	ctl_table ipv4_dir[2];
-	ctl_table root_dir[2];
+
+static ctl_table vs_vars_table[] = {
+	{
+		.ctl_name	= NET_IPV4_VS_LBLC_EXPIRE,
+		.procname	= "lblc_expiration",
+		.data		= &sysctl_ip_vs_lblc_expiration,
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table vs_table[] = {
+	{
+		.ctl_name	= NET_IPV4_VS,
+		.procname	= "vs",
+		.mode		= 0555, 
+		.child		= vs_vars_table
+	},
+	{ .ctl_name = 0 }
 };
 
+static ctl_table ipv4_table[] = {
+	{
+		.ctl_name	= NET_IPV4,
+		.procname	= "ipv4", 
+		.mode		= 0555,
+		.child		= vs_table
+	},
+	{ .ctl_name = 0 }
+};
 
-static struct ip_vs_lblc_sysctl_table lblc_sysctl_table = {
-	NULL,
-	{{NET_IPV4_VS_LBLC_EXPIRE, "lblc_expiration",
-	  &sysctl_ip_vs_lblc_expiration,
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {0}},
-	{{NET_IPV4_VS, "vs", NULL, 0, 0555, lblc_sysctl_table.vs_vars},
-	 {0}},
-	{{NET_IPV4, "ipv4", NULL, 0, 0555, lblc_sysctl_table.vs_dir},
-	 {0}},
-	{{CTL_NET, "net", NULL, 0, 0555, lblc_sysctl_table.ipv4_dir},
-	 {0}}
+static ctl_table lblc_root_table[] = {
+	{
+		.ctl_name	= CTL_NET,
+		.procname	= "net", 
+		.mode		= 0555, 
+		.child		= ipv4_table
+	},
+	{ .ctl_name = 0 }
 };
 
+static struct ctl_table_header * sysctl_header;
 
 /*
  *      new/free a ip_vs_lblc_entry, which is a mapping of a destionation
@@ -586,15 +607,14 @@
 static int __init ip_vs_lblc_init(void)
 {
 	INIT_LIST_HEAD(&ip_vs_lblc_scheduler.n_list);
-	lblc_sysctl_table.sysctl_header =
-		register_sysctl_table(lblc_sysctl_table.root_dir, 0);
+	sysctl_header = register_sysctl_table(lblc_root_table, 0);
 	return register_ip_vs_scheduler(&ip_vs_lblc_scheduler);
 }
 
 
 static void __exit ip_vs_lblc_cleanup(void)
 {
-	unregister_sysctl_table(lblc_sysctl_table.sysctl_header);
+	unregister_sysctl_table(sysctl_header);
 	unregister_ip_vs_scheduler(&ip_vs_lblc_scheduler);
 }
 
diff -Nru a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
--- a/net/ipv4/ipvs/ip_vs_lblcr.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c	Sat Apr  3 19:38:55 2004
@@ -297,29 +297,50 @@
 /*
  *      IPVS LBLCR sysctl table
  */
-struct ip_vs_lblcr_sysctl_table {
-	struct ctl_table_header *sysctl_header;
-	ctl_table vs_vars[2];
-	ctl_table vs_dir[2];
-	ctl_table ipv4_dir[2];
-	ctl_table root_dir[2];
+
+static ctl_table vs_vars_table[] = {
+	{
+		.ctl_name	= NET_IPV4_VS_LBLCR_EXPIRE,
+		.procname	= "lblcr_expiration",
+		.data		= &sysctl_ip_vs_lblcr_expiration,
+		.maxlen		= sizeof(int),
+		.mode		= 0644, 
+		.proc_handler	= &proc_dointvec_jiffies,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table vs_table[] = {
+	{
+		.ctl_name	= NET_IPV4_VS,
+		.procname	= "vs",
+		.mode		= 0555,
+		.child		= vs_vars_table
+	},
+	{ .ctl_name = 0 }
 };
 
+static ctl_table ipv4_table[] = {
+	{
+		.ctl_name	= NET_IPV4,
+		.procname	= "ipv4", 
+		.mode		= 0555,
+		.child		= vs_table
+	},
+	{ .ctl_name = 0 }
+};
 
-static struct ip_vs_lblcr_sysctl_table lblcr_sysctl_table = {
-	NULL,
-	{{NET_IPV4_VS_LBLCR_EXPIRE, "lblcr_expiration",
-	  &sysctl_ip_vs_lblcr_expiration,
-	  sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
-	 {0}},
-	{{NET_IPV4_VS, "vs", NULL, 0, 0555, lblcr_sysctl_table.vs_vars},
-	 {0}},
-	{{NET_IPV4, "ipv4", NULL, 0, 0555, lblcr_sysctl_table.vs_dir},
-	 {0}},
-	{{CTL_NET, "net", NULL, 0, 0555, lblcr_sysctl_table.ipv4_dir},
-	 {0}}
+static ctl_table lblcr_root_table[] = {
+	{
+		.ctl_name	= CTL_NET,
+		.procname	= "net", 
+		.mode		= 0555, 
+		.child		= ipv4_table
+	},
+	{ .ctl_name = 0 }
 };
 
+static struct ctl_table_header * sysctl_header;
 
 /*
  *      new/free a ip_vs_lblcr_entry, which is a mapping of a destination
@@ -844,8 +865,7 @@
 static int __init ip_vs_lblcr_init(void)
 {
 	INIT_LIST_HEAD(&ip_vs_lblcr_scheduler.n_list);
-	lblcr_sysctl_table.sysctl_header =
-		register_sysctl_table(lblcr_sysctl_table.root_dir, 0);
+	sysctl_header = register_sysctl_table(lblcr_root_table, 0);
 #ifdef CONFIG_IP_VS_LBLCR_DEBUG
 	proc_net_create("ip_vs_lblcr", 0, ip_vs_lblcr_getinfo);
 #endif
@@ -858,7 +878,7 @@
 #ifdef CONFIG_IP_VS_LBLCR_DEBUG
 	proc_net_remove("ip_vs_lblcr");
 #endif
-	unregister_sysctl_table(lblcr_sysctl_table.sysctl_header);
+	unregister_sysctl_table(sysctl_header);
 	unregister_ip_vs_scheduler(&ip_vs_lblcr_scheduler);
 }
 
diff -Nru a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
--- a/net/ipv4/netfilter/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/netfilter/Kconfig	Sat Apr  3 19:38:55 2004
@@ -363,7 +363,7 @@
 
 	  Please note that you will need a recent version (>= 1.2.6a)
 	  of the iptables userspace program in order to use this feature.
-	  See http://www.iptables.org/ for download instructions.
+	  See <http://www.iptables.org/> for download instructions.
 
 	  If unsure, say 'N'.
 
@@ -497,7 +497,7 @@
 	  which can only be viewed through syslog.
 
 	  The apropriate userspace logging daemon (ulogd) may be obtained from
-	  http://www.gnumonks.org/projects/ulogd
+	  <http://www.gnumonks.org/projects/ulogd/>
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
diff -Nru a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c
--- a/net/ipv4/netfilter/ip_fw_compat_masq.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/netfilter/ip_fw_compat_masq.c	Sat Apr  3 19:38:55 2004
@@ -221,7 +221,7 @@
 	case IPPROTO_TCP: return "TCP";
 	case IPPROTO_UDP: return "UDP";
 	case IPPROTO_ICMP: return "ICMP";
-	default: return "MORE-CAFFIENE-FOR-RUSTY";
+	default: return "MORE-CAFFEINE-FOR-RUSTY";
 	}
 }
 
diff -Nru a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c	Sat Apr  3 19:38:55 2004
@@ -899,10 +899,10 @@
 		goto err_addr_free;
 		
 	if (cls != ASN1_UNI || con != ASN1_PRI || tag != ASN1_INT)
-		goto err_addr_free;;
+		goto err_addr_free;
 		
 	if (!asn1_uint_decode(ctx, end, &trap->general))
-		goto err_addr_free;;
+		goto err_addr_free;
 		
 	if (!asn1_header_decode(ctx, &end, &cls, &con, &tag))
 		goto err_addr_free;
diff -Nru a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
--- a/net/ipv4/netfilter/ip_nat_standalone.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/netfilter/ip_nat_standalone.c	Sat Apr  3 19:38:55 2004
@@ -124,7 +124,16 @@
 		WRITE_LOCK(&ip_nat_lock);
 		/* Seen it before?  This can happen for loopback, retrans,
 		   or local packets.. */
-		if (!(info->initialized & (1 << maniptype))) {
+		if (!(info->initialized & (1 << maniptype))
+#ifndef CONFIG_IP_NF_NAT_LOCAL
+		    /* If this session has already been confirmed we must not
+		     * touch it again even if there is no mapping set up.
+		     * Can only happen on local->local traffic with
+		     * CONFIG_IP_NF_NAT_LOCAL disabled.
+		     */
+		    && !(ct->status & IPS_CONFIRMED)
+#endif
+		    ) {
 			unsigned int ret;
 
 			if (ct->master
diff -Nru a/net/ipv4/netfilter/ipchains_core.c b/net/ipv4/netfilter/ipchains_core.c
--- a/net/ipv4/netfilter/ipchains_core.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/netfilter/ipchains_core.c	Sat Apr  3 19:38:55 2004
@@ -101,6 +101,7 @@
 #include <linux/stat.h>
 
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
 MODULE_DESCRIPTION("ipchains backwards compatibility layer");
 
 /* Understanding locking in this code: (thanks to Alan Cox for using
diff -Nru a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c	Sat Apr  3 19:38:44 2004
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c	Sat Apr  3 19:38:44 2004
@@ -45,7 +45,7 @@
 	const struct ip_nat_multi_range *mr = targinfo;
 
 	if (strcmp(tablename, "nat") != 0) {
-		DEBUGP("masquerade_check: bad table `%s'.\n", table);
+		DEBUGP("masquerade_check: bad table `%s'.\n", tablename);
 		return 0;
 	}
 	if (targinfosize != IPT_ALIGN(sizeof(*mr))) {
diff -Nru a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
--- a/net/ipv4/netfilter/ipt_REJECT.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv4/netfilter/ipt_REJECT.c	Sat Apr  3 19:38:55 2004
@@ -24,6 +24,9 @@
 #include <net/route.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_REJECT.h>
+#ifdef CONFIG_BRIDGE_NETFILTER
+#include <linux/netfilter_bridge.h>
+#endif
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
@@ -56,7 +59,13 @@
 	struct flowi fl = {};
 	struct rtable *rt;
 
-	if (hook != NF_IP_FORWARD) {
+	/* We don't require ip forwarding to be enabled to be able to
+	 * send a RST reply for bridged traffic. */
+	if (hook != NF_IP_FORWARD
+#ifdef CONFIG_BRIDGE_NETFILTER
+	    || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED)
+#endif
+	   ) {
 		fl.nl_u.ip4_u.daddr = iph->saddr;
 		if (hook == NF_IP_LOCAL_IN)
 			fl.nl_u.ip4_u.saddr = iph->daddr;
diff -Nru a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
--- a/net/ipv4/tcp_diag.c	Sat Apr  3 19:38:40 2004
+++ b/net/ipv4/tcp_diag.c	Sat Apr  3 19:38:40 2004
@@ -167,10 +167,8 @@
 			info->tcpi_snd_wscale = 0;
 			info->tcpi_rcv_wscale = 0;
 		}
-#ifdef CONFIG_INET_ECN
 		if (tp->ecn_flags&TCP_ECN_OK)
 			info->tcpi_options |= TCPI_OPT_ECN;
-#endif
 
 		info->tcpi_rto = (1000000*tp->rto)/HZ;
 		info->tcpi_ato = (1000000*tp->ack.ato)/HZ;
diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c	Sat Apr  3 19:38:54 2004
+++ b/net/ipv4/tcp_input.c	Sat Apr  3 19:38:54 2004
@@ -77,11 +77,7 @@
 int sysctl_tcp_sack = 1;
 int sysctl_tcp_fack = 1;
 int sysctl_tcp_reordering = TCP_FASTRETRANS_THRESH;
-#ifdef CONFIG_INET_ECN
-int sysctl_tcp_ecn = 1;
-#else
 int sysctl_tcp_ecn;
-#endif
 int sysctl_tcp_dsack = 1;
 int sysctl_tcp_app_win = 31;
 int sysctl_tcp_adv_win_scale = 2;
@@ -2051,21 +2047,25 @@
 	 */
 	tp->frto_counter = (tp->frto_counter + 1) % 3;
 }
+
 /*
- * TCP Westwood
- * Functions needed for estimating bandwidth.
+ * TCP Westwood+
  */
 
 /*
- * This function initializes fields used in TCP Westwood.
- * We can't get no information about RTT at this time so
- * we are forced to set it to 0.
+ * @init_westwood
+ * This function initializes fields used in TCP Westwood+. We can't
+ * get no information about RTTmin at this time so we simply set it to
+ * TCP_WESTWOOD_INIT_RTT. This value was chosen to be too conservative
+ * since in this way we're sure it will be updated in a consistent
+ * way as soon as possible. It will reasonably happen within the first
+ * RTT period of the connection lifetime.
  */
+
 static void init_westwood(struct sock *sk)
 {
         struct tcp_opt *tp = tcp_sk(sk);
 
-        tp->westwood.bw_sample = 0;
         tp->westwood.bw_ns_est = 0;
         tp->westwood.bw_est = 0;
         tp->westwood.accounted = 0;
@@ -2080,6 +2080,7 @@
  * @westwood_do_filter
  * Low-pass filter. Implemented using constant coeffients.
  */
+
 static inline __u32 westwood_do_filter(__u32 a, __u32 b)
 {
 	return (((7 * a) + b) >> 3);
@@ -2088,20 +2089,21 @@
 static void westwood_filter(struct sock *sk, __u32 delta)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
-	__u32 sample = tp->westwood.bk / delta;
 
 	tp->westwood.bw_ns_est =
-		westwood_do_filter(tp->westwood.bw_ns_est, sample);
+		westwood_do_filter(tp->westwood.bw_ns_est, 
+				   tp->westwood.bk / delta);
 	tp->westwood.bw_est =
 		westwood_do_filter(tp->westwood.bw_est,
 				   tp->westwood.bw_ns_est);
-	tp->westwood.bw_sample = sample;
 }
 
-/* @westwood_update_rttmin
+/* 
+ * @westwood_update_rttmin
  * It is used to update RTTmin. In this case we MUST NOT use
  * WESTWOOD_RTT_MIN minimum bound since we could be on a LAN!
  */
+
 static inline __u32 westwood_update_rttmin(struct sock *sk)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -2118,9 +2120,9 @@
 
 /*
  * @westwood_acked
- * Evaluate increases for dk. It requires no lock since when it is
- * called lock should already be held. Be careful about it!
+ * Evaluate increases for dk. 
  */
+
 static inline __u32 westwood_acked(struct sock *sk)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -2136,6 +2138,7 @@
  * It returns 0 if we are still evaluating samples in the same RTT
  * window, 1 if the sample has to be considered in the next window.
  */
+
 static int westwood_new_window(struct sock *sk)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -2164,11 +2167,9 @@
 /*
  * @westwood_update_window
  * It updates RTT evaluation window if it is the right moment to do
- * it. If so it calls filter for evaluating bandwidth. Be careful
- * about __westwood_update_window() since it is called without
- * any form of lock. It should be used only for internal purposes.
- * Call westwood_update_window() instead.
+ * it. If so it calls filter for evaluating bandwidth. 
  */
+
 static void __westwood_update_window(struct sock *sk, __u32 now)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -2192,11 +2193,12 @@
 }
 
 /*
- * @__westwood_fast_bw
+ * @__tcp_westwood_fast_bw
  * It is called when we are in fast path. In particular it is called when
  * header prediction is successfull. In such case infact update is
  * straight forward and doesn't need any particular care.
  */
+
 void __tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -2210,7 +2212,7 @@
 
 
 /*
- * @tcp_westwood_dupack_update
+ * @westwood_dupack_update
  * It updates accounted and cumul_ack when receiving a dupack.
  */
 
@@ -2244,6 +2246,7 @@
  * This function evaluates cumul_ack for evaluating dk in case of
  * delayed or partial acks.
  */
+
 static __u32 westwood_acked_count(struct sock *sk)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -2271,11 +2274,12 @@
 
 
 /*
- * @__westwood_slow_bw
+ * @__tcp_westwood_slow_bw
  * It is called when something is going wrong..even if there could
  * be no problems! Infact a simple delayed packet may trigger a
  * dupack. But we need to be careful in such case.
  */
+
 void __tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb)
 {
 	struct tcp_opt *tp = tcp_sk(sk);
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c	Sat Apr  3 19:38:42 2004
+++ b/net/ipv4/tcp_ipv4.c	Sat Apr  3 19:38:42 2004
@@ -1596,7 +1596,7 @@
 	newinet->id = newtp->write_seq ^ jiffies;
 
 	tcp_sync_mss(newsk, dst_pmtu(dst));
-	newtp->advmss = dst_metric(dst, RTAX_ADVMSS);;
+	newtp->advmss = dst_metric(dst, RTAX_ADVMSS);
 	tcp_initialize_rcv_mss(newsk);
 
 	__tcp_v4_hash(newsk, 0);
@@ -1825,12 +1825,15 @@
 	goto discard_it;
 
 do_time_wait:
-	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
-		goto discard_and_relse;
+	if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+		tcp_tw_put((struct tcp_tw_bucket *) sk);
+		goto discard_it;
+	}
 
 	if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
 		TCP_INC_STATS_BH(TcpInErrs);
-		goto discard_and_relse;
+		tcp_tw_put((struct tcp_tw_bucket *) sk);
+		goto discard_it;
 	}
 	switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
 					   skb, th, skb->len)) {
diff -Nru a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
--- a/net/ipv4/xfrm4_policy.c	Sat Apr  3 19:38:54 2004
+++ b/net/ipv4/xfrm4_policy.c	Sat Apr  3 19:38:54 2004
@@ -43,14 +43,10 @@
 }
 
 static struct dst_entry *
-__xfrm4_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *policy)
+__xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
 {
 	struct dst_entry *dst;
 
-	if (!fl->fl4_src)
-		fl->fl4_src = rt->rt_src;
-	if (!fl->fl4_dst)
-		fl->fl4_dst = rt->rt_dst;
 	read_lock_bh(&policy->lock);
 	for (dst = policy->bundles; dst; dst = dst->next) {
 		struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
diff -Nru a/net/ipv6/Makefile b/net/ipv6/Makefile
--- a/net/ipv6/Makefile	Sat Apr  3 19:38:54 2004
+++ b/net/ipv6/Makefile	Sat Apr  3 19:38:54 2004
@@ -19,3 +19,5 @@
 obj-$(CONFIG_NETFILTER)	+= netfilter/
 
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
+
+obj-y += exthdrs_core.o
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Sat Apr  3 19:38:55 2004
+++ b/net/ipv6/addrconf.c	Sat Apr  3 19:38:55 2004
@@ -2553,80 +2553,6 @@
 	return -1;
 }
 
-static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca,
-				u32 pid, u32 seq, int event)
-{
-	struct ifaddrmsg *ifm;
-	struct nlmsghdr  *nlh;
-	struct ifa_cacheinfo ci;
-	unsigned char	 *b = skb->tail;
-
-	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));
-	if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
-	ifm = NLMSG_DATA(nlh);
-	ifm->ifa_family = AF_INET6;	
-	ifm->ifa_prefixlen = 128;
-	ifm->ifa_flags = IFA_F_PERMANENT;
-	ifm->ifa_scope = RT_SCOPE_UNIVERSE;
-	if (ipv6_addr_scope(&ifmca->mca_addr)&IFA_SITE)
-		ifm->ifa_scope = RT_SCOPE_SITE;
-	ifm->ifa_index = ifmca->idev->dev->ifindex;
-	RTA_PUT(skb, IFA_ADDRESS, 16, &ifmca->mca_addr);
-	ci.cstamp = (__u32)(TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) / HZ
-		    * 100 + TIME_DELTA(ifmca->mca_cstamp, INITIAL_JIFFIES) % HZ
-		    * 100 / HZ);
-	ci.tstamp = (__u32)(TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) / HZ
-		    * 100 + TIME_DELTA(ifmca->mca_tstamp, INITIAL_JIFFIES) % HZ
-		    * 100 / HZ);
-	ci.ifa_prefered = INFINITY_LIFE_TIME;
-	ci.ifa_valid = INFINITY_LIFE_TIME;
-	RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);
-	nlh->nlmsg_len = skb->tail - b;
-	return skb->len;
-
-nlmsg_failure:
-rtattr_failure:
-	skb_trim(skb, b - skb->data);
-	return -1;
-}
-
-static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,
-				u32 pid, u32 seq, int event)
-{
-	struct ifaddrmsg *ifm;
-	struct nlmsghdr  *nlh;
-	struct ifa_cacheinfo ci;
-	unsigned char	 *b = skb->tail;
-
-	nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));
-	if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
-	ifm = NLMSG_DATA(nlh);
-	ifm->ifa_family = AF_INET6;	
-	ifm->ifa_prefixlen = 128;
-	ifm->ifa_flags = IFA_F_PERMANENT;
-	ifm->ifa_scope = RT_SCOPE_UNIVERSE;
-	if (ipv6_addr_scope(&ifaca->aca_addr)&IFA_SITE)
-		ifm->ifa_scope = RT_SCOPE_SITE;
-	ifm->ifa_index = ifaca->aca_idev->dev->ifindex;
-	RTA_PUT(skb, IFA_ADDRESS, 16, &ifaca->aca_addr);
-	ci.cstamp = (__u32)(TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) / HZ
-		    * 100 + TIME_DELTA(ifaca->aca_cstamp, INITIAL_JIFFIES) % HZ
-		    * 100 / HZ);
-	ci.tstamp = (__u32)(TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) / HZ
-		    * 100 + TIME_DELTA(ifaca->aca_tstamp, INITIAL_JIFFIES) % HZ
-		    * 100 / HZ);
-	ci.ifa_prefered = INFINITY_LIFE_TIME;
-	ci.ifa_valid = INFINITY_LIFE_TIME;
-	RTA_PUT(skb, IFA_CACHEINFO, sizeof(ci), &ci);
-	nlh->nlmsg_len = skb->tail - b;
-	return skb->len;
-
-nlmsg_failure:
-rtattr_failure:
-	skb_trim(skb, b - skb->data);
-	return -1;
-}
-
 static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	int idx, ip_idx;
@@ -2635,8 +2561,6 @@
 	struct net_device *dev;
 	struct inet6_dev *idev = NULL;
 	struct inet6_ifaddr *ifa;
-	struct ifmcaddr6 *ifmca;
-	struct ifacaddr6 *ifaca;
 	
 	s_idx = cb->args[0];
 	s_ip_idx = ip_idx = cb->args[1];
diff -Nru a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
--- a/net/ipv6/exthdrs.c	Sat Apr  3 19:38:41 2004
+++ b/net/ipv6/exthdrs.c	Sat Apr  3 19:38:41 2004
@@ -633,105 +633,3 @@
 	}
 	return opt2;
 }
-
-
-/* 
- * find out if nexthdr is a well-known extension header or a protocol
- */
-
-int ipv6_ext_hdr(u8 nexthdr)
-{
-	/* 
-	 * find out if nexthdr is an extension header or a protocol
-	 */
-	return ( (nexthdr == NEXTHDR_HOP)	||
-		 (nexthdr == NEXTHDR_ROUTING)	||
-		 (nexthdr == NEXTHDR_FRAGMENT)	||
-		 (nexthdr == NEXTHDR_AUTH)	||
-		 (nexthdr == NEXTHDR_NONE)	||
-		 (nexthdr == NEXTHDR_DEST) );
-}
-
-/*
- * Skip any extension headers. This is used by the ICMP module.
- *
- * Note that strictly speaking this conflicts with RFC 2460 4.0:
- * ...The contents and semantics of each extension header determine whether 
- * or not to proceed to the next header.  Therefore, extension headers must
- * be processed strictly in the order they appear in the packet; a
- * receiver must not, for example, scan through a packet looking for a
- * particular kind of extension header and process that header prior to
- * processing all preceding ones.
- * 
- * We do exactly this. This is a protocol bug. We can't decide after a
- * seeing an unknown discard-with-error flavour TLV option if it's a 
- * ICMP error message or not (errors should never be send in reply to
- * ICMP error messages).
- * 
- * But I see no other way to do this. This might need to be reexamined
- * when Linux implements ESP (and maybe AUTH) headers.
- * --AK
- *
- * This function parses (probably truncated) exthdr set "hdr"
- * of length "len". "nexthdrp" initially points to some place,
- * where type of the first header can be found.
- *
- * It skips all well-known exthdrs, and returns pointer to the start
- * of unparsable area i.e. the first header with unknown type.
- * If it is not NULL *nexthdr is updated by type/protocol of this header.
- *
- * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
- *        - it may return pointer pointing beyond end of packet,
- *	    if the last recognized header is truncated in the middle.
- *        - if packet is truncated, so that all parsed headers are skipped,
- *	    it returns NULL.
- *	  - First fragment header is skipped, not-first ones
- *	    are considered as unparsable.
- *	  - ESP is unparsable for now and considered like
- *	    normal payload protocol.
- *	  - Note also special handling of AUTH header. Thanks to IPsec wizards.
- *
- * --ANK (980726)
- */
-
-int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len)
-{
-	u8 nexthdr = *nexthdrp;
-
-	while (ipv6_ext_hdr(nexthdr)) {
-		struct ipv6_opt_hdr hdr;
-		int hdrlen;
-
-		if (len < (int)sizeof(struct ipv6_opt_hdr))
-			return -1;
-		if (nexthdr == NEXTHDR_NONE)
-			return -1;
-		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
-			BUG();
-		if (nexthdr == NEXTHDR_FRAGMENT) {
-			unsigned short frag_off;
-			if (skb_copy_bits(skb,
-					  start+offsetof(struct frag_hdr,
-							 frag_off),
-					  &frag_off,
-					  sizeof(frag_off))) {
-				return -1;
-			}
-
-			if (ntohs(frag_off) & ~0x7)
-				break;
-			hdrlen = 8;
-		} else if (nexthdr == NEXTHDR_AUTH)
-			hdrlen = (hdr.hdrlen+2)<<2; 
-		else
-			hdrlen = ipv6_optlen(&hdr); 
-
-		nexthdr = hdr.nexthdr;
-		len -= hdrlen;
-		start += hdrlen;
-	}
-
-	*nexthdrp = nexthdr;
-	return start;
-}
-
diff -Nru a/net/ipv6/exthdrs_core.c b/net/ipv6/exthdrs_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv6/exthdrs_core.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,108 @@
+/*
+ * IPv6 library code, needed by static components when full IPv6 support is
+ * not configured or static.
+ */
+#include <net/ipv6.h>
+
+/* 
+ * find out if nexthdr is a well-known extension header or a protocol
+ */
+
+int ipv6_ext_hdr(u8 nexthdr)
+{
+	/* 
+	 * find out if nexthdr is an extension header or a protocol
+	 */
+	return ( (nexthdr == NEXTHDR_HOP)	||
+		 (nexthdr == NEXTHDR_ROUTING)	||
+		 (nexthdr == NEXTHDR_FRAGMENT)	||
+		 (nexthdr == NEXTHDR_AUTH)	||
+		 (nexthdr == NEXTHDR_NONE)	||
+		 (nexthdr == NEXTHDR_DEST) );
+}
+
+/*
+ * Skip any extension headers. This is used by the ICMP module.
+ *
+ * Note that strictly speaking this conflicts with RFC 2460 4.0:
+ * ...The contents and semantics of each extension header determine whether 
+ * or not to proceed to the next header.  Therefore, extension headers must
+ * be processed strictly in the order they appear in the packet; a
+ * receiver must not, for example, scan through a packet looking for a
+ * particular kind of extension header and process that header prior to
+ * processing all preceding ones.
+ * 
+ * We do exactly this. This is a protocol bug. We can't decide after a
+ * seeing an unknown discard-with-error flavour TLV option if it's a 
+ * ICMP error message or not (errors should never be send in reply to
+ * ICMP error messages).
+ * 
+ * But I see no other way to do this. This might need to be reexamined
+ * when Linux implements ESP (and maybe AUTH) headers.
+ * --AK
+ *
+ * This function parses (probably truncated) exthdr set "hdr"
+ * of length "len". "nexthdrp" initially points to some place,
+ * where type of the first header can be found.
+ *
+ * It skips all well-known exthdrs, and returns pointer to the start
+ * of unparsable area i.e. the first header with unknown type.
+ * If it is not NULL *nexthdr is updated by type/protocol of this header.
+ *
+ * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL.
+ *        - it may return pointer pointing beyond end of packet,
+ *	    if the last recognized header is truncated in the middle.
+ *        - if packet is truncated, so that all parsed headers are skipped,
+ *	    it returns NULL.
+ *	  - First fragment header is skipped, not-first ones
+ *	    are considered as unparsable.
+ *	  - ESP is unparsable for now and considered like
+ *	    normal payload protocol.
+ *	  - Note also special handling of AUTH header. Thanks to IPsec wizards.
+ *
+ * --ANK (980726)
+ */
+
+int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len)
+{
+	u8 nexthdr = *nexthdrp;
+
+	while (ipv6_ext_hdr(nexthdr)) {
+		struct ipv6_opt_hdr hdr;
+		int hdrlen;
+
+		if (len < (int)sizeof(struct ipv6_opt_hdr))
+			return -1;
+		if (nexthdr == NEXTHDR_NONE)
+			return -1;
+		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
+			BUG();
+		if (nexthdr == NEXTHDR_FRAGMENT) {
+			unsigned short frag_off;
+			if (skb_copy_bits(skb,
+					  start+offsetof(struct frag_hdr,
+							 frag_off),
+					  &frag_off,
+					  sizeof(frag_off))) {
+				return -1;
+			}
+
+			if (ntohs(frag_off) & ~0x7)
+				break;
+			hdrlen = 8;
+		} else if (nexthdr == NEXTHDR_AUTH)
+			hdrlen = (hdr.hdrlen+2)<<2; 
+		else
+			hdrlen = ipv6_optlen(&hdr); 
+
+		nexthdr = hdr.nexthdr;
+		len -= hdrlen;
+		start += hdrlen;
+	}
+
+	*nexthdrp = nexthdr;
+	return start;
+}
+
+EXPORT_SYMBOL(ipv6_ext_hdr);
+EXPORT_SYMBOL(ipv6_skip_exthdr);
diff -Nru a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
--- a/net/ipv6/ip6_output.c	Sat Apr  3 19:38:41 2004
+++ b/net/ipv6/ip6_output.c	Sat Apr  3 19:38:41 2004
@@ -821,6 +821,9 @@
 						       sk->sk_allocation);
 				if (unlikely(np->cork.opt == NULL))
 					return -ENOBUFS;
+			} else if (np->cork.opt->tot_len < opt->tot_len) {
+				printk(KERN_DEBUG "ip6_append_data: invalid option length\n");
+				return -EINVAL;
 			}
 			memcpy(np->cork.opt, opt, opt->tot_len);
 			inet->cork.flags |= IPCORK_OPT;
diff -Nru a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c
--- a/net/ipv6/ipv6_syms.c	Sat Apr  3 19:38:54 2004
+++ b/net/ipv6/ipv6_syms.c	Sat Apr  3 19:38:54 2004
@@ -41,9 +41,7 @@
 #endif
 EXPORT_SYMBOL(rt6_lookup);
 EXPORT_SYMBOL(fl6_sock_lookup);
-EXPORT_SYMBOL(ipv6_ext_hdr);
 EXPORT_SYMBOL(ip6_append_data);
 EXPORT_SYMBOL(ip6_flush_pending_frames);
 EXPORT_SYMBOL(ip6_push_pending_frames);
 EXPORT_SYMBOL(ipv6_push_nfrag_opts);
-EXPORT_SYMBOL(ipv6_skip_exthdr);
diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
--- a/net/ipv6/tcp_ipv6.c	Sat Apr  3 19:38:44 2004
+++ b/net/ipv6/tcp_ipv6.c	Sat Apr  3 19:38:44 2004
@@ -1639,7 +1639,7 @@
 
 no_tcp_socket:
 	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
-		goto discard_and_relse;
+		goto discard_it;
 
 	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 bad_packet:
@@ -1662,12 +1662,14 @@
 	goto discard_it;
 
 do_time_wait:
-	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
-		goto discard_and_relse;
+	if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+		tcp_tw_put((struct tcp_tw_bucket *) sk);
+		goto discard_it;
+	}
 
 	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 		TCP_INC_STATS_BH(TcpInErrs);
-		sock_put(sk);
+		tcp_tw_put((struct tcp_tw_bucket *) sk);
 		goto discard_it;
 	}
 
diff -Nru a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
--- a/net/ipv6/xfrm6_policy.c	Sat Apr  3 19:38:42 2004
+++ b/net/ipv6/xfrm6_policy.c	Sat Apr  3 19:38:42 2004
@@ -52,7 +52,7 @@
 }
 
 static struct dst_entry *
-__xfrm6_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *policy)
+__xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
 {
 	struct dst_entry *dst;
 
diff -Nru a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c
--- a/net/irda/irlan/irlan_filter.c	Sat Apr  3 19:38:56 2004
+++ b/net/irda/irlan/irlan_filter.c	Sat Apr  3 19:38:56 2004
@@ -53,7 +53,7 @@
 			self->provider.mac_address[4] = 
 				self->provider.send_arb_val & 0xff;
 			self->provider.mac_address[5] = 
-				(self->provider.send_arb_val >> 8) & 0xff;;
+				(self->provider.send_arb_val >> 8) & 0xff;
 		} else {
 			/* Just generate something for now */
 			get_random_bytes(self->provider.mac_address+4, 1);
diff -Nru a/net/irda/irttp.c b/net/irda/irttp.c
--- a/net/irda/irttp.c	Sat Apr  3 19:38:44 2004
+++ b/net/irda/irttp.c	Sat Apr  3 19:38:44 2004
@@ -1271,7 +1271,7 @@
 
 	lsap = (struct lsap_cb *) sap;
 
-	self->max_seg_size = max_seg_size - TTP_HEADER;;
+	self->max_seg_size = max_seg_size - TTP_HEADER;
 	self->max_header_size = max_header_size+TTP_HEADER;
 
 	IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __FUNCTION__, self->stsap_sel);
diff -Nru a/net/key/af_key.c b/net/key/af_key.c
--- a/net/key/af_key.c	Sat Apr  3 19:38:42 2004
+++ b/net/key/af_key.c	Sat Apr  3 19:38:42 2004
@@ -901,6 +901,7 @@
 	struct sadb_sa *sa;
 	struct sadb_key *key;
 	uint16_t proto;
+	int err;
 	
 
 	sa = (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1];
@@ -922,6 +923,9 @@
 	if (proto == 0)
 		return ERR_PTR(-EINVAL);
 
+	/* default error is no buffer space */
+	err = -ENOBUFS;
+
 	/* RFC2367:
 
    Only SADB_SASTATE_MATURE SAs may be submitted in an SADB_ADD message.
@@ -980,8 +984,10 @@
 	if (sa->sadb_sa_auth) {
 		int keysize = 0;
 		struct xfrm_algo_desc *a = xfrm_aalg_get_byid(sa->sadb_sa_auth);
-		if (!a)
+		if (!a) {
+			err = -ENOSYS;
 			goto out;
+		}
 		if (key)
 			keysize = (key->sadb_key_bits + 7) / 8;
 		x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL);
@@ -999,8 +1005,10 @@
 	if (sa->sadb_sa_encrypt) {
 		if (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) {
 			struct xfrm_algo_desc *a = xfrm_calg_get_byid(sa->sadb_sa_encrypt);
-			if (!a)
+			if (!a) {
+				err = -ENOSYS;
 				goto out;
+			}
 			x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL);
 			if (!x->calg)
 				goto out;
@@ -1009,8 +1017,10 @@
 		} else {
 			int keysize = 0;
 			struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt);
-			if (!a)
+			if (!a) {
+				err = -ENOSYS;
 				goto out;
+			}
 			key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
 			if (key)
 				keysize = (key->sadb_key_bits + 7) / 8;
@@ -1030,8 +1040,10 @@
 
 	x->props.family = pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 
 						    &x->props.saddr);
-	if (!x->props.family)
+	if (!x->props.family) {
+		err = -EAFNOSUPPORT;
 		goto out;
+	}
 	pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1], 
 				  &x->id.daddr);
 
@@ -1076,10 +1088,14 @@
 	}
 
 	x->type = xfrm_get_type(proto, x->props.family);
-	if (x->type == NULL)
+	if (x->type == NULL) {
+		err = -ENOPROTOOPT;
 		goto out;
-	if (x->type->init_state(x, NULL))
+	}
+	if (x->type->init_state(x, NULL)) {
+		err = -EINVAL;
 		goto out;
+	}
 	x->km.seq = hdr->sadb_msg_seq;
 	x->km.state = XFRM_STATE_VALID;
 	return x;
@@ -1087,7 +1103,7 @@
 out:
 	x->km.state = XFRM_STATE_DEAD;
 	xfrm_state_put(x);
-	return ERR_PTR(-ENOBUFS);
+	return ERR_PTR(err);
 }
 
 static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
@@ -1683,7 +1699,7 @@
 		sin6->sin6_port = xp->selector.sport;
 		sin6->sin6_flowinfo = 0;
 		memcpy(&sin6->sin6_addr, xp->selector.saddr.a6,
-		       sizeof(struct in6_addr));;
+		       sizeof(struct in6_addr));
 		sin6->sin6_scope_id = 0;
 	}
 #endif
@@ -1863,6 +1879,7 @@
 		err = -EINVAL;
 		goto out;
 	}
+	xp->selector.family = xp->family;
 	xp->selector.prefixlen_s = sa->sadb_address_prefixlen;
 	xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
 	xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
diff -Nru a/net/netlink/netlink_dev.c b/net/netlink/netlink_dev.c
--- a/net/netlink/netlink_dev.c	Sat Apr  3 19:38:43 2004
+++ b/net/netlink/netlink_dev.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 		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 @@
 {
 	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 -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c	Sat Apr  3 19:38:45 2004
+++ b/net/packet/af_packet.c	Sat Apr  3 19:38:45 2004
@@ -34,6 +34,8 @@
  *	Alexey Kuznetsov	:	Untied from IPv4 stack.
  *	Cyrus Durgin		:	Fixed kerneld for kmod.
  *	Michal Ostrowski        :       Module initialization cleanup.
+ *         Ulises Alonso        :       Frame number limit removal and 
+ *                                      packet_set_ring memory leak.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -168,30 +170,47 @@
 
 struct packet_opt
 {
+	struct tpacket_stats	stats;
+#ifdef CONFIG_PACKET_MMAP
+	unsigned long		*pg_vec;
+	unsigned int		head;
+	unsigned int            frames_per_block;
+	unsigned int		frame_size;
+	unsigned int		frame_max;
+	int			copy_thresh;
+#endif
 	struct packet_type	prot_hook;
 	spinlock_t		bind_lock;
 	char			running;	/* prot_hook is attached*/
 	int			ifindex;	/* bound device		*/
 	unsigned short		num;
-	struct tpacket_stats	stats;
 #ifdef CONFIG_PACKET_MULTICAST
 	struct packet_mclist	*mclist;
 #endif
 #ifdef CONFIG_PACKET_MMAP
 	atomic_t		mapped;
-	unsigned long		*pg_vec;
-	unsigned int		pg_vec_order;
+	unsigned int            pg_vec_order;
 	unsigned int		pg_vec_pages;
 	unsigned int		pg_vec_len;
-
-	struct tpacket_hdr	**iovec;
-	unsigned int		frame_size;
-	unsigned int		iovmax;
-	unsigned int		head;
-	int			copy_thresh;
 #endif
 };
 
+#ifdef CONFIG_PACKET_MMAP
+
+static inline unsigned long packet_lookup_frame(struct packet_opt *po, unsigned int position)
+{
+	unsigned int pg_vec_pos, frame_offset;
+	unsigned long frame;
+
+	pg_vec_pos = position / po->frames_per_block;
+	frame_offset = position % po->frames_per_block;
+
+	frame = (unsigned long) (po->pg_vec[pg_vec_pos] + (frame_offset * po->frame_size));
+	
+	return frame;
+}
+#endif
+
 #define pkt_sk(__sk) ((struct packet_opt *)(__sk)->sk_protinfo)
 
 void packet_sock_destruct(struct sock *sk)
@@ -586,11 +605,11 @@
 		snaplen = skb->len-skb->data_len;
 
 	spin_lock(&sk->sk_receive_queue.lock);
-	h = po->iovec[po->head];
-
+	h = (struct tpacket_hdr *)packet_lookup_frame(po, po->head);
+	
 	if (h->tp_status)
 		goto ring_is_full;
-	po->head = po->head != po->iovmax ? po->head+1 : 0;
+	po->head = po->head != po->frame_max ? po->head+1 : 0;
 	po->stats.tp_packets++;
 	if (copy_skb) {
 		status |= TP_STATUS_COPY;
@@ -1485,10 +1504,13 @@
 	unsigned int mask = datagram_poll(file, sock, wait);
 
 	spin_lock_bh(&sk->sk_receive_queue.lock);
-	if (po->iovec) {
-		unsigned last = po->head ? po->head-1 : po->iovmax;
+	if (po->pg_vec) {
+		unsigned last = po->head ? po->head-1 : po->frame_max;
+		struct tpacket_hdr *h;
 
-		if (po->iovec[last]->tp_status)
+		h = (struct tpacket_hdr *)packet_lookup_frame(po, last);
+
+		if (h->tp_status)
 			mask |= POLLIN | POLLRDNORM;
 	}
 	spin_unlock_bh(&sk->sk_receive_queue.lock);
@@ -1548,16 +1570,18 @@
 static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing)
 {
 	unsigned long *pg_vec = NULL;
-	struct tpacket_hdr **io_vec = NULL;
 	struct packet_opt *po = pkt_sk(sk);
 	int was_running, num, order = 0;
 	int err = 0;
-
+	
 	if (req->tp_block_nr) {
 		int i, l;
-		int frames_per_block;
 
 		/* Sanity tests and some calculations */
+
+		if (po->pg_vec)
+			return -EBUSY;
+
 		if ((int)req->tp_block_size <= 0)
 			return -EINVAL;
 		if (req->tp_block_size&(PAGE_SIZE-1))
@@ -1566,10 +1590,11 @@
 			return -EINVAL;
 		if (req->tp_frame_size&(TPACKET_ALIGNMENT-1))
 			return -EINVAL;
-		frames_per_block = req->tp_block_size/req->tp_frame_size;
-		if (frames_per_block <= 0)
+
+		po->frames_per_block = req->tp_block_size/req->tp_frame_size;
+		if (po->frames_per_block <= 0)
 			return -EINVAL;
-		if (frames_per_block*req->tp_block_nr != req->tp_frame_nr)
+		if (po->frames_per_block*req->tp_block_nr != req->tp_frame_nr)
 			return -EINVAL;
 		/* OK! */
 
@@ -1596,20 +1621,16 @@
 		}
 		/* Page vector is allocated */
 
-		/* Draw frames */
-		io_vec = kmalloc(req->tp_frame_nr*sizeof(struct tpacket_hdr*), GFP_KERNEL);
-		if (io_vec == NULL)
-			goto out_free_pgvec;
-		memset(io_vec, 0, req->tp_frame_nr*sizeof(struct tpacket_hdr*));
-
 		l = 0;
 		for (i=0; i<req->tp_block_nr; i++) {
 			unsigned long ptr = pg_vec[i];
+			struct tpacket_hdr *header;
 			int k;
 
-			for (k=0; k<frames_per_block; k++, l++) {
-				io_vec[l] = (struct tpacket_hdr*)ptr;
-				io_vec[l]->tp_status = TP_STATUS_KERNEL;
+			for (k=0; k<po->frames_per_block; k++) {
+				
+				header = (struct tpacket_hdr*)ptr;
+				header->tp_status = TP_STATUS_KERNEL;
 				ptr += req->tp_frame_size;
 			}
 		}
@@ -1642,8 +1663,7 @@
 
 		spin_lock_bh(&sk->sk_receive_queue.lock);
 		pg_vec = XC(po->pg_vec, pg_vec);
-		io_vec = XC(po->iovec, io_vec);
-		po->iovmax = req->tp_frame_nr-1;
+		po->frame_max = req->tp_frame_nr-1;
 		po->head = 0;
 		po->frame_size = req->tp_frame_size;
 		spin_unlock_bh(&sk->sk_receive_queue.lock);
@@ -1652,7 +1672,7 @@
 		req->tp_block_nr = XC(po->pg_vec_len, req->tp_block_nr);
 
 		po->pg_vec_pages = req->tp_block_size/PAGE_SIZE;
-		po->prot_hook.func = po->iovec ? tpacket_rcv : packet_rcv;
+		po->prot_hook.func = po->pg_vec ? tpacket_rcv : packet_rcv;
 		skb_queue_purge(&sk->sk_receive_queue);
 #undef XC
 		if (atomic_read(&po->mapped))
@@ -1669,9 +1689,6 @@
 	spin_unlock(&po->bind_lock);
 
 	release_sock(sk);
-
-	if (io_vec)
-		kfree(io_vec);
 
 out_free_pgvec:
 	if (pg_vec)
diff -Nru a/net/sched/Kconfig b/net/sched/Kconfig
--- a/net/sched/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/net/sched/Kconfig	Sat Apr  3 19:38:55 2004
@@ -164,6 +164,17 @@
 	  To compile this code as a module, choose M here: the
 	  module will be called sch_dsmark.
 
+config NET_SCH_DELAY
+	tristate "Delay simulator"
+	depends on NET_SCHED
+	help
+	  Say Y if you want to delay packets by a fixed amount of
+	  time. This is often useful to simulate network delay when
+	  testing applications or protocols.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sch_delay.
+
 config NET_SCH_INGRESS
 	tristate "Ingress Qdisc"
 	depends on NET_SCHED && NETFILTER
diff -Nru a/net/sched/Makefile b/net/sched/Makefile
--- a/net/sched/Makefile	Sat Apr  3 19:38:43 2004
+++ b/net/sched/Makefile	Sat Apr  3 19:38:43 2004
@@ -22,6 +22,7 @@
 obj-$(CONFIG_NET_SCH_TEQL)	+= sch_teql.o
 obj-$(CONFIG_NET_SCH_PRIO)	+= sch_prio.o
 obj-$(CONFIG_NET_SCH_ATM)	+= sch_atm.o
+obj-$(CONFIG_NET_SCH_DELAY)	+= sch_delay.o
 obj-$(CONFIG_NET_CLS_U32)	+= cls_u32.o
 obj-$(CONFIG_NET_CLS_ROUTE4)	+= cls_route.o
 obj-$(CONFIG_NET_CLS_FW)	+= cls_fw.o
diff -Nru a/net/sched/sch_delay.c b/net/sched/sch_delay.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/sched/sch_delay.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,269 @@
+/*
+ * net/sched/sch_delay.c	Simple constant delay
+ *
+ * 		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.
+ *
+ * Authors:	Stephen Hemminger <shemminger@osdl.org>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/notifier.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+
+/*	Network delay simulator
+	This scheduler adds a fixed delay to all packets.
+	Similar to NISTnet and BSD Dummynet.
+
+	It uses byte fifo underneath similar to TBF */
+struct dly_sched_data {
+	u32	latency;
+	u32	limit;
+	struct timer_list timer;
+	struct Qdisc *qdisc;
+};
+
+/* Time stamp put into socket buffer control block */
+struct dly_skb_cb {
+	psched_time_t	queuetime;
+};
+
+/* Enqueue packets with underlying discipline (fifo)
+ * but mark them with current time first.
+ */
+static int dly_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+	struct dly_skb_cb *cb = (struct dly_skb_cb *)skb->cb;
+	int ret;
+
+	PSCHED_GET_TIME(cb->queuetime);
+
+	/* Queue to underlying scheduler */
+	ret = q->qdisc->enqueue(skb, q->qdisc);
+	if (ret)
+		sch->stats.drops++;
+	else {
+		sch->q.qlen++;
+		sch->stats.bytes += skb->len;
+		sch->stats.packets++;
+	}
+	return 0;
+}
+
+/* Requeue packets but don't change time stamp */
+static int dly_requeue(struct sk_buff *skb, struct Qdisc *sch)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+	int ret;
+
+	ret = q->qdisc->ops->requeue(skb, q->qdisc);
+	if (ret == 0)
+		sch->q.qlen++;
+	return ret;
+}
+
+static unsigned int dly_drop(struct Qdisc *sch)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+	unsigned int len;
+
+	len = q->qdisc->ops->drop(q->qdisc);
+	if (len) {
+		sch->q.qlen--;
+		sch->stats.drops++;
+	}
+	return len;
+}
+
+/* Dequeue packet.
+ * If packet needs to be held up, then stop the
+ * queue and set timer to wakeup later.
+ */
+static struct sk_buff *dly_dequeue(struct Qdisc *sch)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+	struct sk_buff *skb = q->qdisc->dequeue(q->qdisc);
+
+	if (skb) {
+		struct dly_skb_cb *cb = (struct dly_skb_cb *)skb->cb;
+		psched_time_t now;
+		long diff;
+
+		PSCHED_GET_TIME(now);
+		diff = q->latency - PSCHED_TDIFF(now, cb->queuetime);
+
+		if (diff <= 0) {
+			sch->q.qlen--;
+			sch->flags &= ~TCQ_F_THROTTLED;
+			return skb;
+		}
+
+		if (!netif_queue_stopped(sch->dev)) {
+			long delay = PSCHED_US2JIFFIE(diff);
+			if (delay <= 0)
+				delay = 1;
+			mod_timer(&q->timer, jiffies+delay);
+		}
+
+		if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
+			sch->q.qlen--;
+			sch->stats.drops++;
+		}
+		sch->flags |= TCQ_F_THROTTLED;
+	}
+	return NULL;
+}
+
+static void dly_reset(struct Qdisc *sch)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+
+	qdisc_reset(q->qdisc);
+	sch->q.qlen = 0;
+	sch->flags &= ~TCQ_F_THROTTLED;
+	del_timer(&q->timer);
+}
+
+static void dly_timer(unsigned long arg)
+{
+	struct Qdisc *sch = (struct Qdisc *)arg;
+
+	sch->flags &= ~TCQ_F_THROTTLED;
+	netif_schedule(sch->dev);
+}
+
+/* Tell Fifo the new limit. */
+static int change_limit(struct Qdisc *q, u32 limit)
+{
+	struct rtattr *rta;
+	int ret;
+
+	rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
+	if (!rta)
+		return -ENOMEM;
+
+	rta->rta_type = RTM_NEWQDISC;
+	((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
+	ret = q->ops->change(q, rta);
+	kfree(rta);
+
+	return ret;
+}
+
+/* Setup underlying FIFO discipline */
+static int dly_change(struct Qdisc *sch, struct rtattr *opt)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+	struct tc_dly_qopt *qopt = RTA_DATA(opt);
+	int err;
+
+	if (q->qdisc == &noop_qdisc) {
+		struct Qdisc *child
+			= qdisc_create_dflt(sch->dev, &bfifo_qdisc_ops);
+		if (!child)
+			return -EINVAL;
+		q->qdisc = child;
+	}
+
+	err = change_limit(q->qdisc, qopt->limit);
+	if (err) {
+		qdisc_destroy(q->qdisc);
+		q->qdisc = &noop_qdisc;
+	} else {
+		q->latency = qopt->latency;
+		q->limit = qopt->limit;
+	}
+	return err;
+}
+
+static int dly_init(struct Qdisc *sch, struct rtattr *opt)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+
+	if (!opt)
+		return -EINVAL;
+
+	init_timer(&q->timer);
+	q->timer.function = dly_timer;
+	q->timer.data = (unsigned long) sch;
+	q->qdisc = &noop_qdisc;
+
+	return dly_change(sch, opt);
+}
+
+static void dly_destroy(struct Qdisc *sch)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+
+	del_timer(&q->timer);
+	qdisc_destroy(q->qdisc);
+	q->qdisc = &noop_qdisc;
+}
+
+static int dly_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+	struct dly_sched_data *q = (struct dly_sched_data *)sch->data;
+	unsigned char	 *b = skb->tail;
+	struct tc_dly_qopt qopt;
+
+	qopt.latency = q->latency;
+	qopt.limit = q->limit;
+
+	RTA_PUT(skb, TCA_OPTIONS, sizeof(qopt), &qopt);
+
+	return skb->len;
+
+rtattr_failure:
+	skb_trim(skb, b - skb->data);
+	return -1;
+}
+
+static struct Qdisc_ops dly_qdisc_ops = {
+	.id		=	"delay",
+	.priv_size	=	sizeof(struct dly_sched_data),
+	.enqueue	=	dly_enqueue,
+	.dequeue	=	dly_dequeue,
+	.requeue	=	dly_requeue,
+	.drop		=	dly_drop,
+	.init		=	dly_init,
+	.reset		=	dly_reset,
+	.destroy	=	dly_destroy,
+	.change		=	dly_change,
+	.dump		=	dly_dump,
+	.owner		=	THIS_MODULE,
+};
+
+
+static int __init dly_module_init(void)
+{
+	return register_qdisc(&dly_qdisc_ops);
+}
+static void __exit dly_module_exit(void)
+{
+	unregister_qdisc(&dly_qdisc_ops);
+}
+module_init(dly_module_init)
+module_exit(dly_module_exit)
+MODULE_LICENSE("GPL");
diff -Nru a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
--- a/net/sched/sch_hfsc.c	Sat Apr  3 19:38:41 2004
+++ b/net/sched/sch_hfsc.c	Sat Apr  3 19:38:41 2004
@@ -118,7 +118,7 @@
 
 struct hfsc_class
 {
-	u32	classid;	/* class id */
+	u32		classid;	/* class id */
 	unsigned int	refcnt;		/* usage count */
 
 	struct tc_stats	stats;		/* generic statistics */
@@ -138,28 +138,28 @@
 	struct list_head hlist;		/* hash list member */
 	struct list_head dlist;		/* drop list member */
 
-	u64	cl_total;	/* total work in bytes */
-	u64	cl_cumul;	/* cumulative work in bytes done by
+	u64	cl_total;		/* total work in bytes */
+	u64	cl_cumul;		/* cumulative work in bytes done by
 					   real-time criteria */
 
-	u64 	cl_d;		/* deadline*/
-	u64 	cl_e;		/* eligible time */
-	u64	cl_vt;		/* virtual time */
-	u64	cl_f;		/* time when this class will fit for
+	u64 	cl_d;			/* deadline*/
+	u64 	cl_e;			/* eligible time */
+	u64	cl_vt;			/* virtual time */
+	u64	cl_f;			/* time when this class will fit for
 					   link-sharing, max(myf, cfmin) */
-	u64	cl_myf;		/* my fit-time (calculated from this
+	u64	cl_myf;			/* my fit-time (calculated from this
 					   class's own upperlimit curve) */
-	u64	cl_myfadj;	/* my fit-time adjustment (to cancel
+	u64	cl_myfadj;		/* my fit-time adjustment (to cancel
 					   history dependence) */
-	u64	cl_cfmin;	/* earliest children's fit-time (used
+	u64	cl_cfmin;		/* earliest children's fit-time (used
 					   with cl_myf to obtain cl_f) */
-	u64	cl_cvtmin;	/* minimal virtual time among the
+	u64	cl_cvtmin;		/* minimal virtual time among the
 					   children fit for link-sharing
 					   (monotonic within a period) */
-	u64	cl_vtadj;	/* intra-period cumulative vt
+	u64	cl_vtadj;		/* intra-period cumulative vt
 					   adjustment */
-	u64	cl_vtoff;	/* inter-period cumulative vt offset */
-	u64	cl_cvtmax;	/* max child's vt in the last period */
+	u64	cl_vtoff;		/* inter-period cumulative vt offset */
+	u64	cl_cvtmax;		/* max child's vt in the last period */
 
 	struct internal_sc cl_rsc;	/* internal real-time service curve */
 	struct internal_sc cl_fsc;	/* internal fair service curve */
@@ -179,15 +179,13 @@
 
 struct hfsc_sched
 {
-	u16	defcls;			/* default class id */
-
+	u16	defcls;				/* default class id */
 	struct hfsc_class root;			/* root class */
-	struct hfsc_class *last_xmit;		/* class that transmitted last
-						   packet (for requeueing) */
 	struct list_head clhash[HFSC_HSIZE];	/* class hash */
 	struct list_head eligible;		/* eligible list */
 	struct list_head droplist;		/* active leaf class list (for
 						   dropping) */
+	struct sk_buff_head requeue;		/* requeued packet */
 	struct timer_list wd_timer;		/* watchdog timer */
 };
 
@@ -566,8 +564,7 @@
  * service curve starting at (x, y).
  */
 static void
-rtsc_init(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x,
-                                                            u64 y)
+rtsc_init(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
 {
 	rtsc->x	   = x;
 	rtsc->y    = y;
@@ -626,8 +623,7 @@
  * runtime service curve and the service curve starting at (x, y).
  */
 static void
-rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x,
-                                                           u64 y)
+rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u64 x, u64 y)
 {
 	u64 y1, y2, dx, dy;
 	u32 dsm;
@@ -1231,9 +1227,6 @@
 	list_del(&cl->siblings);
 	hfsc_adjust_levels(cl->cl_parent);
 	hfsc_purge_queue(sch, cl);
-	if (q->last_xmit == cl)
-		q->last_xmit = NULL;
-
 	if (--cl->refcnt == 0)
 		hfsc_destroy_class(sch, cl);
 
@@ -1541,6 +1534,7 @@
 		INIT_LIST_HEAD(&q->clhash[i]);
 	INIT_LIST_HEAD(&q->eligible);
 	INIT_LIST_HEAD(&q->droplist);
+	skb_queue_head_init(&q->requeue);
 
 	q->root.refcnt  = 1;
 	q->root.classid = sch->handle;
@@ -1568,7 +1562,7 @@
 	struct tc_hfsc_qopt *qopt;
 
 	if (opt == NULL || RTA_PAYLOAD(opt) < sizeof(*qopt))
-		return -EINVAL;;
+		return -EINVAL;
 	qopt = RTA_DATA(opt);
 
 	sch_tree_lock(sch);
@@ -1619,10 +1613,9 @@
 		list_for_each_entry(cl, &q->clhash[i], hlist)
 			hfsc_reset_class(cl);
 	}
-
+	__skb_queue_purge(&q->requeue);
 	INIT_LIST_HEAD(&q->eligible);
 	INIT_LIST_HEAD(&q->droplist);
-	q->last_xmit = NULL;
 	del_timer(&q->wd_timer);
 	sch->flags &= ~TCQ_F_THROTTLED;
 	sch->q.qlen = 0;
@@ -1639,7 +1632,7 @@
 		list_for_each_entry_safe(cl, next, &q->clhash[i], hlist)
 			hfsc_destroy_class(sch, cl);
 	}
-
+	__skb_queue_purge(&q->requeue);
 	del_timer(&q->wd_timer);
 }
 
@@ -1708,6 +1701,8 @@
 
 	if (sch->q.qlen == 0)
 		return NULL;
+	if ((skb = __skb_dequeue(&q->requeue)))
+		goto out;
 
 	PSCHED_GET_TIME(cur_time);
 
@@ -1757,7 +1752,7 @@
 		set_passive(cl);
 	}
 
-	q->last_xmit = cl;
+ out:
 	sch->flags &= ~TCQ_F_THROTTLED;
 	sch->q.qlen--;
 
@@ -1768,28 +1763,10 @@
 hfsc_requeue(struct sk_buff *skb, struct Qdisc *sch)
 {
 	struct hfsc_sched *q = (struct hfsc_sched *)sch->data;
-	struct hfsc_class *cl = q->last_xmit;
-	unsigned int len = skb->len;
-	int ret;
 
-	if (cl == NULL) {
-		kfree_skb(skb);
-		sch->stats.drops++;
-		return NET_XMIT_DROP;
-	}
-
-	ret = cl->qdisc->ops->requeue(skb, cl->qdisc);
-	if (ret == NET_XMIT_SUCCESS) {
-		if (cl->qdisc->q.qlen == 1)
-			set_active(cl, len);
-		sch->q.qlen++;
-	} else {
-		cl->stats.drops++;
-		sch->stats.drops++;
-	}
-	q->last_xmit = NULL;
-
-	return ret;
+	__skb_queue_head(&q->requeue, skb);
+	sch->q.qlen++;
+	return NET_XMIT_SUCCESS;
 }
 
 static unsigned int
diff -Nru a/net/sched/sch_htb.c b/net/sched/sch_htb.c
--- a/net/sched/sch_htb.c	Sat Apr  3 19:38:44 2004
+++ b/net/sched/sch_htb.c	Sat Apr  3 19:38:44 2004
@@ -21,9 +21,11 @@
  *			created test case so that I was able to fix nasty bug
  *		Wilfried Weissmann
  *			spotted bug in dequeue code and helped with fix
+ *		Jiri Fojtasek
+ *			fixed requeue routine
  *		and many others. thanks.
  *
- * $Id: sch_htb.c,v 1.24 2003/07/28 15:25:23 devik Exp devik $
+ * $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -74,7 +76,7 @@
 #define HTB_HYSTERESIS 1/* whether to use mode hysteresis for speedup */
 #define HTB_QLOCK(S) spin_lock_bh(&(S)->dev->queue_lock)
 #define HTB_QUNLOCK(S) spin_unlock_bh(&(S)->dev->queue_lock)
-#define HTB_VER 0x3000f	/* major must be matched with number suplied by TC as version */
+#define HTB_VER 0x30010	/* major must be matched with number suplied by TC as version */
 
 #if HTB_VER >> 16 != TC_HTB_PROTOVER
 #error "Mismatched sch_htb.c and pkt_sch.h"
@@ -437,13 +439,13 @@
 		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;
@@ -708,7 +710,7 @@
 
     sch->q.qlen++;
     sch->stats.packets++; sch->stats.bytes += skb->len;
-    HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",htb_classid(cl),skb);
+    HTB_DBG(1,1,"htb_enq_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb);
     return NET_XMIT_SUCCESS;
 }
 
@@ -717,16 +719,18 @@
 {
     struct htb_sched *q = (struct htb_sched *)sch->data;
     struct htb_class *cl = htb_classify(skb,sch);
+    struct sk_buff *tskb;
 
     if (cl == HTB_DIRECT || !cl) {
 	/* enqueue to helper queue */
 	if (q->direct_queue.qlen < q->direct_qlen && cl) {
-	    __skb_queue_tail(&q->direct_queue, skb);
-	    q->direct_pkts++;
+	    __skb_queue_head(&q->direct_queue, skb);
 	} else {
-	    kfree_skb (skb);
-	    sch->stats.drops++;
-	    return NET_XMIT_DROP;
+            __skb_queue_head(&q->direct_queue, skb);
+            tskb = __skb_dequeue_tail(&q->direct_queue);
+            kfree_skb (tskb);
+            sch->stats.drops++;
+            return NET_XMIT_CN;	
 	}
     } else if (cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q) != NET_XMIT_SUCCESS) {
 	sch->stats.drops++;
@@ -736,7 +740,7 @@
 	    htb_activate (q,cl);
 
     sch->q.qlen++;
-    HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",htb_classid(cl),skb);
+    HTB_DBG(1,1,"htb_req_ok cl=%X skb=%p\n",(cl && cl != HTB_DIRECT)?cl->classid:0,skb);
     return NET_XMIT_SUCCESS;
 }
 
@@ -869,7 +873,7 @@
 		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 +1052,7 @@
 		/* 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
@@ -1487,7 +1491,7 @@
 		cl->magic = HTB_CMAGIC;
 #endif
 
-		/* create leaf qdisc early because it uses kmalloc(GPF_KERNEL)
+		/* create leaf qdisc early because it uses kmalloc(GFP_KERNEL)
 		   so that can't be used inside of sch_tree_lock
 		   -- thanks to Karlis Peisenieks */
 		new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops);
diff -Nru a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
--- a/net/sched/sch_tbf.c	Sat Apr  3 19:38:41 2004
+++ b/net/sched/sch_tbf.c	Sat Apr  3 19:38:41 2004
@@ -62,7 +62,7 @@
 
 	Algorithm.
 	----------
-	
+
 	Let N(t_i) be B/R initially and N(t) grow continuously with time as:
 
 	N(t+delta) = min{B/R, N(t) + delta}
@@ -146,15 +146,15 @@
 		if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch))
 #endif
 			kfree_skb(skb);
-	
+
 		return NET_XMIT_DROP;
 	}
-	
+
 	if ((ret = q->qdisc->enqueue(skb, q->qdisc)) != 0) {
 		sch->stats.drops++;
 		return ret;
-	}	
-	
+	}
+
 	sch->q.qlen++;
 	sch->stats.bytes += skb->len;
 	sch->stats.packets++;
@@ -165,10 +165,10 @@
 {
 	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
 	int ret;
-	
+
 	if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0)
-		sch->q.qlen++; 
-	
+		sch->q.qlen++;
+
 	return ret;
 }
 
@@ -176,7 +176,7 @@
 {
 	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
 	unsigned int len;
-	
+
 	if ((len = q->qdisc->ops->drop(q->qdisc)) != 0) {
 		sch->q.qlen--;
 		sch->stats.drops++;
@@ -196,7 +196,7 @@
 {
 	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
 	struct sk_buff *skb;
-	
+
 	skb = q->qdisc->dequeue(q->qdisc);
 
 	if (skb) {
@@ -204,7 +204,7 @@
 		long toks;
 		long ptoks = 0;
 		unsigned int len = skb->len;
-		
+
 		PSCHED_GET_TIME(now);
 
 		toks = PSCHED_TDIFF_SAFE(now, q->t_c, q->buffer, 0);
@@ -248,13 +248,13 @@
 		   This is the main idea of all FQ algorithms
 		   (cf. CSZ, HPFQ, HFSC)
 		 */
-		
+
 		if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) {
-			/* When requeue fails skb is dropped */ 
+			/* When requeue fails skb is dropped */
 			sch->q.qlen--;
 			sch->stats.drops++;
-		}	
-		
+		}
+
 		sch->flags |= TCQ_F_THROTTLED;
 		sch->stats.overlimits++;
 	}
@@ -279,24 +279,24 @@
 	struct Qdisc *q = qdisc_create_dflt(dev, &bfifo_qdisc_ops);
         struct rtattr *rta;
 	int ret;
-	
+
 	if (q) {
 		rta = kmalloc(RTA_LENGTH(sizeof(struct tc_fifo_qopt)), GFP_KERNEL);
 		if (rta) {
 			rta->rta_type = RTM_NEWQDISC;
 			rta->rta_len = RTA_LENGTH(sizeof(struct tc_fifo_qopt)); 
 			((struct tc_fifo_qopt *)RTA_DATA(rta))->limit = limit;
-			
+
 			ret = q->ops->change(q, rta);
 			kfree(rta);
-			
+
 			if (ret == 0)
 				return q;
 		}
 		qdisc_destroy(q);
 	}
 
-	return NULL;	
+	return NULL;
 }
 
 static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
@@ -340,7 +340,7 @@
 	}
 	if (max_size < 0)
 		goto done;
-	
+
 	if (q->qdisc == &noop_qdisc) {
 		if ((child = tbf_create_dflt_qdisc(sch->dev, qopt->limit)) == NULL)
 			goto done;
@@ -369,17 +369,17 @@
 static int tbf_init(struct Qdisc* sch, struct rtattr *opt)
 {
 	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
-	
+
 	if (opt == NULL)
 		return -EINVAL;
-	
+
 	PSCHED_GET_TIME(q->t_c);
 	init_timer(&q->wd_timer);
 	q->wd_timer.function = tbf_watchdog;
 	q->wd_timer.data = (unsigned long)sch;
 
 	q->qdisc = &noop_qdisc;
-	
+
 	return tbf_change(sch, opt);
 }
 
@@ -393,7 +393,7 @@
 		qdisc_put_rtab(q->P_tab);
 	if (q->R_tab)
 		qdisc_put_rtab(q->R_tab);
-	
+
 	qdisc_destroy(q->qdisc);
 	q->qdisc = &noop_qdisc;
 }
@@ -404,10 +404,10 @@
 	unsigned char	 *b = skb->tail;
 	struct rtattr *rta;
 	struct tc_tbf_qopt opt;
-	
+
 	rta = (struct rtattr*)b;
 	RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
-	
+
 	opt.limit = q->limit;
 	opt.rate = q->R_tab->rate;
 	if (q->P_tab)
@@ -427,15 +427,14 @@
 }
 
 static int tbf_dump_class(struct Qdisc *sch, unsigned long cl,
-	       		  struct sk_buff *skb, struct tcmsg *tcm)
+			  struct sk_buff *skb, struct tcmsg *tcm)
 {
 	struct tbf_sched_data *q = (struct tbf_sched_data*)sch->data;
 
-	if (cl != 1) 	/* only one class */ 
+	if (cl != 1) 	/* only one class */
 		return -ENOENT;
-    
-	tcm->tcm_parent = TC_H_ROOT;
-	tcm->tcm_handle = 1;
+
+	tcm->tcm_handle |= TC_H_MIN(1);
 	tcm->tcm_info = q->qdisc->handle;
 
 	return 0;
@@ -449,12 +448,12 @@
 	if (new == NULL)
 		new = &noop_qdisc;
 
-	sch_tree_lock(sch);	
+	sch_tree_lock(sch);
 	*old = xchg(&q->qdisc, new);
 	qdisc_reset(*old);
 	sch->q.qlen = 0;
 	sch_tree_unlock(sch);
-	
+
 	return 0;
 }
 
@@ -474,7 +473,7 @@
 }
 
 static int tbf_change_class(struct Qdisc *sch, u32 classid, u32 parentid, 
-			struct rtattr **tca, unsigned long *arg)
+			    struct rtattr **tca, unsigned long *arg)
 {
 	return -ENOSYS;
 }
@@ -486,11 +485,9 @@
 
 static void tbf_walk(struct Qdisc *sch, struct qdisc_walker *walker)
 {
-	struct tbf_sched_data *q = (struct tbf_sched_data *)sch->data;
-
 	if (!walker->stop) {
-		if (walker->count >= walker->skip) 
-			if (walker->fn(sch, (unsigned long)q, walker) < 0) { 
+		if (walker->count >= walker->skip)
+			if (walker->fn(sch, 1, walker) < 0) {
 				walker->stop = 1;
 				return;
 			}
@@ -500,7 +497,7 @@
 
 static struct Qdisc_class_ops tbf_class_ops =
 {
-	.graft		= 	tbf_graft,
+	.graft		=	tbf_graft,
 	.leaf		=	tbf_leaf,
 	.get		=	tbf_get,
 	.put		=	tbf_put,
@@ -532,7 +529,7 @@
 	return register_qdisc(&tbf_qdisc_ops);
 }
 
-static void __exit tbf_module_exit(void) 
+static void __exit tbf_module_exit(void)
 {
 	unregister_qdisc(&tbf_qdisc_ops);
 }
diff -Nru a/net/sctp/Kconfig b/net/sctp/Kconfig
--- a/net/sctp/Kconfig	Sat Apr  3 19:38:41 2004
+++ b/net/sctp/Kconfig	Sat Apr  3 19:38:41 2004
@@ -5,14 +5,9 @@
 menu "SCTP Configuration (EXPERIMENTAL)"
 	depends on INET && EXPERIMENTAL
 
-config IPV6_SCTP__
-	tristate
-	default y if IPV6=n
-	default IPV6 if IPV6
-
 config IP_SCTP
 	tristate "The SCTP Protocol (EXPERIMENTAL)"
-	depends on IPV6_SCTP__
+	depends on IPV6 || IPV6=n
 	---help---
 	  Stream Control Transmission Protocol
 
@@ -61,6 +56,7 @@
 choice
 	prompt "SCTP: Cookie HMAC Algorithm"
 	depends on IP_SCTP
+	default SCTP_HMAC_MD5
 	help
 	  HMAC algorithm to be used during association initialization.  It
 	  is strongly recommended to use HMAC-SHA1 or HMAC-MD5.  See 
diff -Nru a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
--- a/net/sctp/bind_addr.c	Sat Apr  3 19:38:55 2004
+++ b/net/sctp/bind_addr.c	Sat Apr  3 19:38:55 2004
@@ -292,7 +292,7 @@
 		if (retval) {
 			/* Can't finish building the list, clean up. */
 			sctp_bind_addr_clean(bp);
-			break;;
+			break;
 		}
 
 		len = ntohs(param->length);
diff -Nru a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
--- a/net/sctp/sm_make_chunk.c	Sat Apr  3 19:38:41 2004
+++ b/net/sctp/sm_make_chunk.c	Sat Apr  3 19:38:41 2004
@@ -516,7 +516,7 @@
 	 */
 	dp.tsn = 0;
 	dp.stream = htons(sinfo->sinfo_stream);
-	dp.ppid   = htonl(sinfo->sinfo_ppid);
+	dp.ppid   = sinfo->sinfo_ppid;
 
 	/* Set the flags for an unordered send.  */
 	if (sinfo->sinfo_flags & MSG_UNORDERED) {
@@ -1467,7 +1467,7 @@
 struct __sctp_missing {
 	__u32 num_missing;
 	__u16 type;
-}  __attribute__((packed));;
+}  __attribute__((packed));
 
 /*
  * Report a missing mandatory parameter.
diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c
--- a/net/sctp/socket.c	Sat Apr  3 19:38:57 2004
+++ b/net/sctp/socket.c	Sat Apr  3 19:38:57 2004
@@ -4490,7 +4490,7 @@
 	 * 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
 	 */
 	skb_queue_head_init(&newsp->pd_lobby);
-	sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;;
+	sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode;
 
 	if (sctp_sk(oldsk)->pd_mode) {
 		struct sk_buff_head *queue;
diff -Nru a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
--- a/net/sctp/ulpevent.c	Sat Apr  3 19:38:41 2004
+++ b/net/sctp/ulpevent.c	Sat Apr  3 19:38:41 2004
@@ -663,7 +663,7 @@
 	 * for and this information is passed opaquely by the SCTP stack from
 	 * one end to the other.
 	 */
-	info->sinfo_ppid = ntohl(chunk->subh.data_hdr->ppid);
+	info->sinfo_ppid = chunk->subh.data_hdr->ppid;
 
 	/* Sockets API Extensions for SCTP
 	 * Section 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
diff -Nru a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
--- a/net/sunrpc/auth_gss/svcauth_gss.c	Sat Apr  3 19:38:43 2004
+++ b/net/sunrpc/auth_gss/svcauth_gss.c	Sat Apr  3 19:38:43 2004
@@ -193,7 +193,7 @@
 	len = qword_get(&mesg, buf, mlen);
 	status = -EINVAL;
 	if (len < 0)
-		goto out;;
+		goto out;
 	status = -ENOMEM;
 	if (dup_to_netobj(&rsii.in_token, buf, len))
 		goto out;
diff -Nru a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
--- a/net/sunrpc/auth_unix.c	Sat Apr  3 19:38:44 2004
+++ b/net/sunrpc/auth_unix.c	Sat Apr  3 19:38:44 2004
@@ -149,7 +149,7 @@
 	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 @@
 	/*
 	 * 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 -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Sat Apr  3 19:38:42 2004
+++ b/net/sunrpc/clnt.c	Sat Apr  3 19:38:42 2004
@@ -102,19 +102,22 @@
 {
 	struct rpc_version	*version;
 	struct rpc_clnt		*clnt = NULL;
+	int err;
 	int len;
 
 	dprintk("RPC: creating %s client for %s (xprt %p)\n",
 		program->name, servname, xprt);
 
+	err = -EINVAL;
 	if (!xprt)
-		goto out;
+		goto out_err;
 	if (vers >= program->nrvers || !(version = program->version[vers]))
-		goto out;
+		goto out_err;
 
+	err = -ENOMEM;
 	clnt = (struct rpc_clnt *) kmalloc(sizeof(*clnt), GFP_KERNEL);
 	if (!clnt)
-		goto out_no_clnt;
+		goto out_err;
 	memset(clnt, 0, sizeof(*clnt));
 	atomic_set(&clnt->cl_users, 0);
 	atomic_set(&clnt->cl_count, 1);
@@ -149,9 +152,11 @@
 	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 @@
 	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 @@
 	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);
 }
 
 /*
@@ -610,9 +610,6 @@
 	rcvbuf->tail[0].iov_len  = 0;
 	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;
diff -Nru a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
--- a/net/sunrpc/pmap_clnt.c	Sat Apr  3 19:38:43 2004
+++ b/net/sunrpc/pmap_clnt.c	Sat Apr  3 19:38:43 2004
@@ -65,9 +65,11 @@
 	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 @@
 			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 @@
 	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 @@
 	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 -Nru a/net/sunrpc/sched.c b/net/sunrpc/sched.c
--- a/net/sunrpc/sched.c	Sat Apr  3 19:38:43 2004
+++ b/net/sunrpc/sched.c	Sat Apr  3 19:38:43 2004
@@ -530,6 +530,9 @@
 			if (!task->tk_action)
 				break;
 			task->tk_action(task);
+			/* micro-optimization to avoid spinlock */
+			if (RPC_IS_RUNNING(task))
+				continue;
 		}
 
 		/*
@@ -545,29 +548,31 @@
 		}
 		spin_unlock_bh(&rpc_queue_lock);
 
-		while (RPC_IS_SLEEPING(task)) {
-			/* sync task: sleep here */
-			dprintk("RPC: %4d sync task going to sleep\n",
-							task->tk_pid);
-			if (current->pid == rpciod_pid)
-				printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
+		if (!RPC_IS_SLEEPING(task))
+			continue;
+		/* sync task: sleep here */
+		dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid);
+		if (current->pid == rpciod_pid)
+			printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
 
+		if (!task->tk_client->cl_intr) {
 			__wait_event(task->tk_wait, !RPC_IS_SLEEPING(task));
-			dprintk("RPC: %4d sync task resuming\n", task->tk_pid);
-
+		} else {
+			__wait_event_interruptible(task->tk_wait, !RPC_IS_SLEEPING(task), status);
 			/*
 			 * When a sync task receives a signal, it exits with
 			 * -ERESTARTSYS. In order to catch any callbacks that
 			 * clean up after sleeping on some queue, we don't
 			 * break the loop here, but go around once more.
 			 */
-			if (task->tk_client->cl_intr && signalled()) {
+			if (status == -ERESTARTSYS) {
 				dprintk("RPC: %4d got signal\n", task->tk_pid);
 				task->tk_flags |= RPC_TASK_KILLED;
 				rpc_exit(task, -ERESTARTSYS);
 				rpc_wake_up_task(task);
 			}
 		}
+		dprintk("RPC: %4d sync task resuming\n", task->tk_pid);
 	}
 
 	if (task->tk_exit) {
diff -Nru a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
--- a/net/sunrpc/sunrpc_syms.c	Sat Apr  3 19:38:55 2004
+++ b/net/sunrpc/sunrpc_syms.c	Sat Apr  3 19:38:55 2004
@@ -63,6 +63,8 @@
 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 -Nru a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c
--- a/net/sunrpc/sysctl.c	Sat Apr  3 19:38:41 2004
+++ b/net/sunrpc/sysctl.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 	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 @@
 		.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 -Nru a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
--- a/net/sunrpc/xdr.c	Sat Apr  3 19:38:54 2004
+++ b/net/sunrpc/xdr.c	Sat Apr  3 19:38:54 2004
@@ -54,7 +54,7 @@
 }
 
 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 -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Sat Apr  3 19:38:45 2004
+++ b/net/sunrpc/xprt.c	Sat Apr  3 19:38:45 2004
@@ -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_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 @@
 		/* 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 @@
 	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 @@
 	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 @@
 		task->tk_status = -EIO;
 
 	switch (task->tk_status) {
+	case -ECONNREFUSED:
+	case -ECONNRESET:
 	case -ENOTCONN:
 		rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
 		return;
@@ -1313,10 +1304,9 @@
 	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 +1320,14 @@
 /*
  * 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 +1341,7 @@
 	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 +1372,7 @@
 	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 +1403,9 @@
 	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 +1413,33 @@
 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 +1447,15 @@
 	spin_lock_init(&xprt->xprt_lock);
 	init_waitqueue_head(&xprt->cong_wait);
 
+	INIT_LIST_HEAD(&xprt->free);
 	INIT_LIST_HEAD(&xprt->recv);
+	INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt);
 	INIT_WORK(&xprt->task_cleanup, xprt_socket_autoclose, xprt);
 	init_timer(&xprt->timer);
 	xprt->timer.function = xprt_init_autodisconnect;
 	xprt->timer.data = (unsigned long) xprt;
 	xprt->last_used = jiffies;
+	xprt->port = XPRT_MAX_RESVPORT;
 
 	/* Set timeout parameters */
 	if (to) {
@@ -1473,15 +1470,16 @@
 	INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog");
 
 	/* initialize free list */
-	for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++)
-		req->rq_next = req + 1;
-	req->rq_next = NULL;
-	xprt->free = xprt->slot;
+	for (req = &xprt->slot[entries-1]; req >= &xprt->slot[0]; req--)
+		list_add(&req->rq_list, &xprt->free);
+
+	xprt_init_xid(xprt);
 
 	/* Check whether we want to use a reserved port */
 	xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
 
-	dprintk("RPC:      created transport %p\n", xprt);
+	dprintk("RPC:      created transport %p with %u slots\n", xprt,
+			xprt->max_reqs);
 	
 	return xprt;
 }
@@ -1489,31 +1487,28 @@
 /*
  * 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 +1558,11 @@
 		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 +1571,7 @@
  * 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 +1587,7 @@
 	}
 
 	/* 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 +1608,11 @@
 	struct rpc_xprt	*xprt;
 
 	xprt = xprt_setup(proto, sap, to);
-	if (!xprt)
-		goto out_bad;
-
-	dprintk("RPC:      xprt_create_proto created xprt %p\n", xprt);
+	if (IS_ERR(xprt))
+		dprintk("RPC:      xprt_create_proto failed\n");
+	else
+		dprintk("RPC:      xprt_create_proto created xprt %p\n", xprt);
 	return xprt;
- out_bad:
-	dprintk("RPC:      xprt_create_proto failed\n");
-	if (xprt)
-		kfree(xprt);
-	return NULL;
 }
 
 /*
@@ -1662,6 +1651,7 @@
 	dprintk("RPC:      destroying transport %p\n", xprt);
 	xprt_shutdown(xprt);
 	xprt_close(xprt);
+	kfree(xprt->slot);
 	kfree(xprt);
 
 	return 0;
diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c	Sat Apr  3 19:38:44 2004
+++ b/net/unix/af_unix.c	Sat Apr  3 19:38:44 2004
@@ -691,7 +691,7 @@
 			goto put_fail;
 
 		if (u->sk_type == type)
-			update_atime(nd.dentry->d_inode);
+			touch_atime(nd.mnt, nd.dentry);
 
 		path_release(&nd);
 
@@ -707,7 +707,7 @@
 			struct dentry *dentry;
 			dentry = unix_sk(u)->dentry;
 			if (dentry)
-				update_atime(dentry->d_inode);
+				touch_atime(unix_sk(u)->mnt, dentry);
 		} else
 			goto fail;
 	}
diff -Nru a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
--- a/net/xfrm/xfrm_policy.c	Sat Apr  3 19:38:43 2004
+++ b/net/xfrm/xfrm_policy.c	Sat Apr  3 19:38:43 2004
@@ -646,13 +646,13 @@
  */
 
 static struct dst_entry *
-xfrm_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *policy, unsigned short family)
+xfrm_find_bundle(struct flowi *fl, struct xfrm_policy *policy, unsigned short family)
 {
 	struct dst_entry *x;
 	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
 	if (unlikely(afinfo == NULL))
 		return ERR_PTR(-EINVAL);
-	x = afinfo->find_bundle(fl, rt, policy);
+	x = afinfo->find_bundle(fl, policy);
 	xfrm_policy_put_afinfo(afinfo);
 	return x;
 }
@@ -762,7 +762,7 @@
 		 * LATER: help from flow cache. It is optional, this
 		 * is required only for output policy.
 		 */
-		dst = xfrm_find_bundle(fl, rt, policy, family);
+		dst = xfrm_find_bundle(fl, policy, family);
 		if (IS_ERR(dst)) {
 			xfrm_pol_put(policy);
 			return PTR_ERR(dst);
diff -Nru a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
--- a/net/xfrm/xfrm_user.c	Sat Apr  3 19:38:44 2004
+++ b/net/xfrm/xfrm_user.c	Sat Apr  3 19:38:44 2004
@@ -674,6 +674,7 @@
 		struct xfrm_tmpl *kp = &xp->xfrm_vec[i];
 
 		memcpy(&up->id, &kp->id, sizeof(up->id));
+		up->family = xp->family;
 		memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr));
 		up->reqid = kp->reqid;
 		up->mode = kp->mode;
diff -Nru a/scripts/Makefile b/scripts/Makefile
--- a/scripts/Makefile	Sat Apr  3 19:38:43 2004
+++ b/scripts/Makefile	Sat Apr  3 19:38:43 2004
@@ -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 @@
 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 -Nru a/scripts/Makefile.build b/scripts/Makefile.build
--- a/scripts/Makefile.build	Sat Apr  3 19:38:55 2004
+++ b/scripts/Makefile.build	Sat Apr  3 19:38:55 2004
@@ -162,7 +162,7 @@
 	$(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 -Nru a/scripts/Makefile.lib b/scripts/Makefile.lib
--- a/scripts/Makefile.lib	Sat Apr  3 19:38:43 2004
+++ b/scripts/Makefile.lib	Sat Apr  3 19:38:43 2004
@@ -249,7 +249,7 @@
 	@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 -Nru a/scripts/Makefile.modpost b/scripts/Makefile.modpost
--- a/scripts/Makefile.modpost	Sat Apr  3 19:38:44 2004
+++ b/scripts/Makefile.modpost	Sat Apr  3 19:38:44 2004
@@ -14,7 +14,7 @@
 modules := $(patsubst %.o,%.ko,$(wildcard $(__modules:.ko=.o)))
 
 ifneq ($(filter-out $(modules),$(__modules)),)
-  $(warning Trouble: $(__modules) )
+  $(warning Trouble: $(filter-out $(modules),$(__modules)))
   $(warning *** Uh-oh, you have stale module entries. You messed with SUBDIRS,)
   $(warning     do not complain if something goes wrong.)
 endif
diff -Nru a/scripts/basic/Makefile b/scripts/basic/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/scripts/basic/Makefile	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/scripts/basic/docproc.c b/scripts/basic/docproc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/scripts/basic/docproc.c	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/scripts/basic/fixdep.c	Sat Apr  3 19:38:43 2004
@@ -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 are 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 -Nru a/scripts/basic/split-include.c b/scripts/basic/split-include.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/scripts/basic/split-include.c	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/scripts/docproc.c b/scripts/docproc.c
--- a/scripts/docproc.c	Sat Apr  3 19:38:41 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/scripts/fixdep.c b/scripts/fixdep.c
--- a/scripts/fixdep.c	Sat Apr  3 19:38:43 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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 -Nru a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
--- a/scripts/kconfig/Makefile	Sat Apr  3 19:38:56 2004
+++ b/scripts/kconfig/Makefile	Sat Apr  3 19:38:56 2004
@@ -8,7 +8,7 @@
 	$< arch/$(ARCH)/Kconfig
 
 gconfig: $(obj)/gconf
-	./$<  arch/$(ARCH)/Kconfig
+	$< arch/$(ARCH)/Kconfig
 
 menuconfig: $(obj)/mconf
 	$(Q)$(MAKE) $(build)=scripts/lxdialog
@@ -95,7 +95,7 @@
 HOSTCFLAGS_lex.zconf.o	:= -I$(src)
 HOSTCFLAGS_zconf.tab.o	:= -I$(src)
 
-HOSTLOADLIBES_qconf	= -L$(QTDIR)/lib -L$(QTDIR)/lib64 -Wl,-rpath,$(QTDIR)/lib -l$(QTLIB) -ldl
+HOSTLOADLIBES_qconf	= -L$(QTLIBPATH) -Wl,-rpath,$(QTLIBPATH) -l$(QTLIB) -ldl
 HOSTCXXFLAGS_qconf.o	= -I$(QTDIR)/include 
 
 HOSTLOADLIBES_gconf	= `pkg-config gtk+-2.0 gmodule-2.0 libglade-2.0 --libs`
@@ -107,6 +107,7 @@
 
 ifeq ($(qconf-target),1)
 MOC = $(QTDIR)/bin/moc
+QTLIBPATH = $(QTDIR)/lib
 -include $(obj)/.tmp_qtcheck
 
 # QT needs some extra effort...
@@ -122,9 +123,12 @@
 	  echo "*"; \
 	  false; \
 	fi; \
-	LIB=qt; \
-	if [ -f $$DIR/lib/libqt-mt.so ]; then LIB=qt-mt; fi; \
-	echo "QTDIR=$$DIR" > $@; echo "QTLIB=$$LIB" >> $@; \
+	LIBPATH=$$DIR/lib; LIB=qt; \
+	$(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
+	  LIBPATH=$$DIR/lib/$$($(HOSTCXX) -print-multi-os-directory); \
+	if [ -f $$LIBPATH/libqt-mt.so ]; then LIB=qt-mt; fi; \
+	echo "QTDIR=$$DIR" > $@; echo "QTLIBPATH=$$LIBPATH" >> $@; \
+	echo "QTLIB=$$LIB" >> $@; \
 	if [ ! -x $$DIR/bin/moc -a -x /usr/bin/moc ]; then \
 	  echo "*"; \
 	  echo "* Unable to find $$DIR/bin/moc, using /usr/bin/moc instead."; \
diff -Nru a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
--- a/scripts/kconfig/confdata.c	Sat Apr  3 19:38:56 2004
+++ b/scripts/kconfig/confdata.c	Sat Apr  3 19:38:56 2004
@@ -229,6 +229,8 @@
 	}
 	fclose(in);
 
+	if (modules_sym)
+		sym_calc_value(modules_sym);
 	for_all_symbols(i, sym) {
 		sym_calc_value(sym);
 		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
@@ -269,8 +271,14 @@
 
 	dirname[0] = 0;
 	if (name && name[0]) {
-		char *slash = strrchr(name, '/');
-		if (slash) {
+		struct stat st;
+		char *slash;
+
+		if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+			strcpy(dirname, name);
+			strcat(dirname, "/");
+			basename = conf_def_filename;
+		} else if ((slash = strrchr(name, '/'))) {
 			int size = slash - name + 1;
 			memcpy(dirname, name, size);
 			dirname[size] = 0;
diff -Nru a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
--- a/scripts/kconfig/expr.c	Sat Apr  3 19:38:42 2004
+++ b/scripts/kconfig/expr.c	Sat Apr  3 19:38:42 2004
@@ -10,6 +10,8 @@
 #define LKC_DIRECT_LINK
 #include "lkc.h"
 
+#define DEBUG_EXPR	0
+
 struct expr *expr_alloc_symbol(struct symbol *sym)
 {
 	struct expr *e = malloc(sizeof(*e));
@@ -220,10 +222,12 @@
 		/* panic */;
 	}
 
-	print_expr(0, e1, 0);
-	printf(" = ");
-	print_expr(0, e2, 0);
-	printf(" ?\n");
+	if (DEBUG_EXPR) {
+		expr_fprint(e1, stdout);
+		printf(" = ");
+		expr_fprint(e2, stdout);
+		printf(" ?\n");
+	}
 
 	return 0;
 }
@@ -397,11 +401,13 @@
 			return expr_alloc_symbol(&symbol_yes);
 	}
 
-	printf("optimize ");
-	print_expr(0, e1, 0);
-	printf(" || ");
-	print_expr(0, e2, 0);
-	printf(" ?\n");
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") || (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
 	return NULL;
 }
 
@@ -444,6 +450,11 @@
 		// (a) && (a!='n') -> (a)
 		return expr_alloc_symbol(sym1);
 
+	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+		// (a) && (a!='m') -> (a='y')
+		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
 	if (sym1->type == S_TRISTATE) {
 		if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
 			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
@@ -483,11 +494,14 @@
 		    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
 			return NULL;
 	}
-	printf("optimize ");
-	print_expr(0, e1, 0);
-	printf(" && ");
-	print_expr(0, e2, 0);
-	printf(" ?\n");
+
+	if (DEBUG_EXPR) {
+		printf("optimize (");
+		expr_fprint(e1, stdout);
+		printf(") && (");
+		expr_fprint(e2, stdout);
+		printf(")?\n");
+	}
 	return NULL;
 }
 
@@ -1073,11 +1087,3 @@
 {
 	expr_print(e, expr_print_file_helper, out, E_NONE);
 }
-
-void print_expr(int mask, struct expr *e, int prevtoken)
-{
-	if (!(cdebug & mask))
-		return;
-	expr_fprint(e, stdout);
-}
-
diff -Nru a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
--- a/scripts/kconfig/expr.h	Sat Apr  3 19:38:44 2004
+++ b/scripts/kconfig/expr.h	Sat Apr  3 19:38:44 2004
@@ -174,7 +174,6 @@
 struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
 
 void expr_fprint(struct expr *e, FILE *out);
-void print_expr(int mask, struct expr *e, int prevtoken);
 
 static inline int expr_is_yes(struct expr *e)
 {
diff -Nru a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
--- a/scripts/kconfig/qconf.cc	Sat Apr  3 19:38:41 2004
+++ b/scripts/kconfig/qconf.cc	Sat Apr  3 19:38:41 2004
@@ -17,9 +17,6 @@
 #include <qheader.h>
 #include <qfiledialog.h>
 #include <qregexp.h>
-#if QT_VERSION >= 300
-#include <qsettings.h>
-#endif
 
 #include <stdlib.h>
 
@@ -30,10 +27,55 @@
 #include "images.c"
 
 static QApplication *configApp;
+
+ConfigSettings::ConfigSettings()
+	: showAll(false), showName(false), showRange(false), showData(false)
+{
+}
+
 #if QT_VERSION >= 300
-static QSettings *configSettings;
+/**
+ * Reads the list column settings from the application settings.
+ */
+void ConfigSettings::readListSettings()
+{
+	showAll = readBoolEntry("/kconfig/qconf/showAll", false);
+	showName = readBoolEntry("/kconfig/qconf/showName", false);
+	showRange = readBoolEntry("/kconfig/qconf/showRange", false);
+	showData = readBoolEntry("/kconfig/qconf/showData", false);
+}
+
+/**
+ * Reads a list of integer values from the application settings.
+ */
+QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+{
+	QValueList<int> result;
+	QStringList entryList = readListEntry(key, ok);
+	if (ok) {
+		QStringList::Iterator it;
+		for (it = entryList.begin(); it != entryList.end(); ++it)
+			result.push_back((*it).toInt());
+	}
+
+	return result;
+}
+
+/**
+ * Writes a list of integer values to the application settings.
+ */
+bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value)
+{
+	QStringList stringList;
+	QValueList<int>::ConstIterator it;
+
+	for (it = value.begin(); it != value.end(); ++it)
+		stringList.push_back(QString::number(*it));
+	return writeEntry(key, stringList);
+}
 #endif
 
+
 /*
  * update all the children of a menu entry
  *   removes/adds the entries from the parent widget as necessary
@@ -327,7 +369,7 @@
 	hide();
 }
 
-ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv)
+ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv, ConfigSettings* configSettings)
 	: Parent(p), cview(cv),
 	  updateAll(false),
 	  symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
@@ -348,6 +390,13 @@
 	connect(this, SIGNAL(selectionChanged(void)),
 		SLOT(updateSelection(void)));
 
+	if (configSettings) {
+		showAll = configSettings->showAll;
+		showName = configSettings->showName;
+		showRange = configSettings->showRange;
+		showData = configSettings->showData;
+	}
+
 	for (i = 0; i < colNr; i++)
 		colMap[i] = colRevMap[i] = -1;
 	addColumn(promptColIdx, "Option");
@@ -702,10 +751,11 @@
 
 ConfigView* ConfigView::viewList;
 
-ConfigView::ConfigView(QWidget* parent, ConfigMainWindow* cview)
+ConfigView::ConfigView(QWidget* parent, ConfigMainWindow* cview,
+		       ConfigSettings *configSettings)
 	: Parent(parent)
 {
-	list = new ConfigList(this, cview);
+	list = new ConfigList(this, cview, configSettings);
 	lineEdit = new ConfigLineEdit(this);
 	lineEdit->hide();
 
@@ -747,13 +797,12 @@
 ConfigMainWindow::ConfigMainWindow(void)
 {
 	QMenuBar* menu;
-	QSplitter* split1;
-	QSplitter* split2;
 	bool ok;
 	int x, y, width, height;
 
 	QWidget *d = configApp->desktop();
 
+	ConfigSettings* configSettings = new ConfigSettings();
 #if QT_VERSION >= 300
 	width = configSettings->readNumEntry("/kconfig/qconf/window width", d->width() - 64);
 	height = configSettings->readNumEntry("/kconfig/qconf/window height", d->height() - 64);
@@ -763,26 +812,29 @@
 		y = configSettings->readNumEntry("/kconfig/qconf/window y", 0, &ok);
 	if (ok)
 		move(x, y);
+	showDebug = configSettings->readBoolEntry("/kconfig/qconf/showDebug", false);
+
+	// read list settings into configSettings, will be used later for ConfigList setup
+	configSettings->readListSettings();
 #else
 	width = d->width() - 64;
 	height = d->height() - 64;
 	resize(width, height);
-#endif
-
 	showDebug = false;
+#endif
 
 	split1 = new QSplitter(this);
 	split1->setOrientation(QSplitter::Horizontal);
 	setCentralWidget(split1);
 
-	menuView = new ConfigView(split1, this);
+	menuView = new ConfigView(split1, this, configSettings);
 	menuList = menuView->list;
 
 	split2 = new QSplitter(split1);
 	split2->setOrientation(QSplitter::Vertical);
 
 	// create config tree
-	configView = new ConfigView(split2, this);
+	configView = new ConfigView(split2, this, configSettings);
 	configList = configView->list;
 
 	helpText = new QTextView(split2);
@@ -886,7 +938,27 @@
 	connect(menuList, SIGNAL(gotFocus(void)),
 		SLOT(listFocusChanged(void)));
 
+#if QT_VERSION >= 300
+	QString listMode = configSettings->readEntry("/kconfig/qconf/listMode", "symbol");
+	if (listMode == "single")
+		showSingleView();
+	else if (listMode == "full")
+		showFullView();
+	else /*if (listMode == "split")*/
+		showSplitView();
+
+	// UI setup done, restore splitter positions
+	QValueList<int> sizes = configSettings->readSizes("/kconfig/qconf/split1", &ok);
+	if (ok)
+		split1->setSizes(sizes);
+
+	sizes = configSettings->readSizes("/kconfig/qconf/split2", &ok);
+	if (ok)
+		split2->setSizes(sizes);
+#else
 	showSplitView();
+#endif
+	delete configSettings;
 }
 
 static QString print_filter(const char *str)
@@ -1234,6 +1306,43 @@
 	QMessageBox::information(this, "qconf", str);
 }
 
+void ConfigMainWindow::saveSettings(void)
+{
+#if QT_VERSION >= 300
+	ConfigSettings *configSettings = new ConfigSettings;
+	configSettings->writeEntry("/kconfig/qconf/window x", pos().x());
+	configSettings->writeEntry("/kconfig/qconf/window y", pos().y());
+	configSettings->writeEntry("/kconfig/qconf/window width", size().width());
+	configSettings->writeEntry("/kconfig/qconf/window height", size().height());
+	configSettings->writeEntry("/kconfig/qconf/showName", configList->showName);
+	configSettings->writeEntry("/kconfig/qconf/showRange", configList->showRange);
+	configSettings->writeEntry("/kconfig/qconf/showData", configList->showData);
+	configSettings->writeEntry("/kconfig/qconf/showAll", configList->showAll);
+	configSettings->writeEntry("/kconfig/qconf/showDebug", showDebug);
+
+	QString entry;
+	switch(configList->mode) {
+	case singleMode :
+		entry = "single";
+		break;
+
+	case symbolMode :
+		entry = "split";
+		break;
+
+	case fullMode :
+		entry = "full";
+		break;
+	}
+	configSettings->writeEntry("/kconfig/qconf/listMode", entry);
+
+	configSettings->writeSizes("/kconfig/qconf/split1", split1->sizes());
+	configSettings->writeSizes("/kconfig/qconf/split2", split2->sizes());
+
+	delete configSettings;
+#endif
+}
+
 void fixup_rootmenu(struct menu *menu)
 {
 	struct menu *child;
@@ -1269,9 +1378,6 @@
 
 	progname = av[0];
 	configApp = new QApplication(ac, av);
-#if QT_VERSION >= 300
-	configSettings = new QSettings;
-#endif
 	if (ac > 1 && av[1][0] == '-') {
 		switch (av[1][1]) {
 		case 'h':
@@ -1294,14 +1400,8 @@
 	//zconfdump(stdout);
 	v->show();
 	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
+	configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
 	configApp->exec();
 
-#if QT_VERSION >= 300
-	configSettings->writeEntry("/kconfig/qconf/window x", v->pos().x());
-	configSettings->writeEntry("/kconfig/qconf/window y", v->pos().y());
-	configSettings->writeEntry("/kconfig/qconf/window width", v->size().width());
-	configSettings->writeEntry("/kconfig/qconf/window height", v->size().height());
-	delete configSettings;
-#endif
 	return 0;
 }
diff -Nru a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
--- a/scripts/kconfig/qconf.h	Sat Apr  3 19:38:43 2004
+++ b/scripts/kconfig/qconf.h	Sat Apr  3 19:38:43 2004
@@ -4,17 +4,39 @@
  */
 
 #include <qlistview.h>
+#if QT_VERSION >= 300
+#include <qsettings.h>
+#else
+class QSettings { };
+#endif
 
 class ConfigList;
 class ConfigItem;
 class ConfigLineEdit;
 class ConfigMainWindow;
 
+
+class ConfigSettings : public QSettings {
+public:
+	ConfigSettings();
+
+#if QT_VERSION >= 300
+	void readListSettings();
+	QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok);
+	bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value);
+#endif
+
+	bool showAll;
+	bool showName;
+	bool showRange;
+	bool showData;
+};
+
 class ConfigView : public QVBox {
 	Q_OBJECT
 	typedef class QVBox Parent;
 public:
-	ConfigView(QWidget* parent, ConfigMainWindow* cview);
+	ConfigView(QWidget* parent, ConfigMainWindow* cview, ConfigSettings* configSettings);
 	~ConfigView(void);
 	static void updateList(ConfigItem* item);
 	static void updateListAll(void);
@@ -38,7 +60,7 @@
 	Q_OBJECT
 	typedef class QListView Parent;
 public:
-	ConfigList(ConfigView* p, ConfigMainWindow* cview);
+	ConfigList(ConfigView* p, ConfigMainWindow* cview, ConfigSettings *configSettings);
 	void reinit(void);
 	ConfigView* parent(void) const
 	{
@@ -222,6 +244,7 @@
 	void setShowData(bool);
 	void showIntro(void);
 	void showAbout(void);
+	void saveSettings(void);
 
 protected:
 	void closeEvent(QCloseEvent *e);
@@ -233,6 +256,8 @@
 	QTextView *helpText;
 	QToolBar *toolBar;
 	QAction *backAction;
+	QSplitter* split1;
+	QSplitter* split2;
 
 	bool showDebug;
 };
diff -Nru a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
--- a/scripts/kconfig/symbol.c	Sat Apr  3 19:38:42 2004
+++ b/scripts/kconfig/symbol.c	Sat Apr  3 19:38:42 2004
@@ -31,6 +31,7 @@
 
 int sym_change_count;
 struct symbol *modules_sym;
+tristate modules_val;
 
 void sym_add_default(struct symbol *sym, const char *def)
 {
@@ -79,11 +80,8 @@
 	if (type == S_TRISTATE) {
 		if (sym_is_choice_value(sym) && sym->visible == yes)
 			type = S_BOOLEAN;
-		else {
-			sym_calc_value(modules_sym);
-			if (modules_sym->curr.tri == no)
-				type = S_BOOLEAN;
-		}
+		else if (modules_val == no)
+			type = S_BOOLEAN;
 	}
 	return type;
 }
@@ -153,6 +151,8 @@
 		prop->visible.tri = expr_calc_value(prop->visible.expr);
 		tri = E_OR(tri, prop->visible.tri);
 	}
+	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
+		tri = yes;
 	if (sym->visible != tri) {
 		sym->visible = tri;
 		sym_set_changed(sym);
@@ -162,6 +162,8 @@
 	tri = no;
 	if (sym->rev_dep.expr)
 		tri = expr_calc_value(sym->rev_dep.expr);
+	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
+		tri = yes;
 	if (sym->rev_dep.tri != tri) {
 		sym->rev_dep.tri = tri;
 		sym_set_changed(sym);
@@ -268,14 +270,8 @@
 				newval.tri = expr_calc_value(prop->expr);
 			}
 		}
-		if (sym_get_type(sym) == S_BOOLEAN) {
-			if (newval.tri == mod)
-				newval.tri = yes;
-			if (sym->visible == mod)
-				sym->visible = yes;
-			if (sym->rev_dep.tri == mod)
-				sym->rev_dep.tri = yes;
-		}
+		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
+			newval.tri = yes;
 		break;
 	case S_STRING:
 	case S_HEX:
@@ -307,6 +303,8 @@
 
 	if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
 		sym_set_changed(sym);
+	if (modules_sym == sym)
+		modules_val = modules_sym->curr.tri;
 
 	if (sym_is_choice(sym)) {
 		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
@@ -327,6 +325,8 @@
 	for_all_symbols(i, sym)
 		sym->flags &= ~SYMBOL_VALID;
 	sym_change_count++;
+	if (modules_sym)
+		sym_calc_value(modules_sym);
 }
 
 void sym_set_changed(struct symbol *sym)
diff -Nru a/scripts/modpost.c b/scripts/modpost.c
--- a/scripts/modpost.c	Sat Apr  3 19:38:41 2004
+++ b/scripts/modpost.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 	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 @@
 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;
 
@@ -141,26 +141,14 @@
 	symbolhash[hash] = new;
 }
 
-#define DOTSYM_PFX "__dot_"
-
 struct symbol *
 find_symbol(const char *name)
 {
 	struct symbol *s;
-	char dotname[64 + sizeof(DOTSYM_PFX)];
 
-	/* .foo matches foo.  PPC64 needs this. */
-	if (name[0] == '.') {
+	/* For our purposes, .foo matches foo.  PPC64 needs this. */
+	if (name[0] == '.')
 		name++;
-		strcpy(dotname, DOTSYM_PFX);
-		strncat(dotname, name, sizeof(dotname) - sizeof(DOTSYM_PFX) - 1);
-		dotname[sizeof(dotname)-1] = 0;
-		/* Sparc32 wants .foo to match __dot_foo, try this first. */
-		for (s = symbolhash[tdb_hash(dotname) % SYMBOL_HASH_SIZE]; s; s=s->next) {
-			if (strcmp(s->name, dotname) == 0)
-				return s;
-		}
-	}
 
 	for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s=s->next) {
 		if (strcmp(s->name, name) == 0)
@@ -204,6 +192,42 @@
 	if (map == MAP_FAILED)
 		return NULL;
 	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
diff -Nru a/scripts/modpost.h b/scripts/modpost.h
--- a/scripts/modpost.h	Sat Apr  3 19:38:31 2004
+++ b/scripts/modpost.h	Sat Apr  3 19:38:31 2004
@@ -53,6 +53,9 @@
 
 #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 @@
 			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 -Nru a/scripts/split-include.c b/scripts/split-include.c
--- a/scripts/split-include.c	Sat Apr  3 19:38:42 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -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;
-}
diff -Nru a/scripts/sumversion.c b/scripts/sumversion.c
--- a/scripts/sumversion.c	Sat Apr  3 19:38:54 2004
+++ b/scripts/sumversion.c	Sat Apr  3 19:38:54 2004
@@ -323,12 +323,12 @@
  * 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 @@
 		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 @@
 
 	   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");
-
-	end = strstr(p, "\n\n");
-	if (!end) {
-		fprintf(stderr, "Warning: could not find end line in %s\n",
-			cmd);
-		goto out_file;
-	}
+	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;
 
-	while (p < end) {
-		unsigned int len;
+		/* 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++;
+		}
 
-		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)) {
+		/* 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 @@
 out_file:
 	release_file(file, flen);
 out:
+	free(dir);
 	free(cmd);
 	return ret;
 }
diff -Nru a/scripts/ver_linux b/scripts/ver_linux
--- a/scripts/ver_linux	Sat Apr  3 19:38:44 2004
+++ b/scripts/ver_linux	Sat Apr  3 19:38:44 2004
@@ -21,8 +21,9 @@
 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 -Nru a/security/commoncap.c b/security/commoncap.c
--- a/security/commoncap.c	Sat Apr  3 19:38:42 2004
+++ b/security/commoncap.c	Sat Apr  3 19:38:42 2004
@@ -22,6 +22,7 @@
 #include <linux/netlink.h>
 #include <linux/ptrace.h>
 #include <linux/xattr.h>
+#include <linux/hugetlb.h>
 
 int cap_capable (struct task_struct *tsk, int cap)
 {
@@ -303,7 +304,7 @@
  * succeed and -ENOMEM implies there is not.
  *
  * We currently support three overcommit policies, which are set via the
- * vm.overcommit_memory sysctl.  See Documentation/vm/overcommit-acounting
+ * vm.overcommit_memory sysctl.  See Documentation/vm/overcommit-accounting
  *
  * Strict overcommit modes added 2002 Feb 26 by Alan Cox.
  * Additional code 2002 Jul 20 by Robert Love.
@@ -358,7 +359,8 @@
 		return -ENOMEM;
 	}
 
-	allowed = totalram_pages * sysctl_overcommit_ratio / 100;
+	allowed = (totalram_pages - hugetlb_total_pages())
+	       	* sysctl_overcommit_ratio / 100;
 	allowed += total_swap_pages;
 
 	if (atomic_read(&vm_committed_space) < allowed)
diff -Nru a/security/dummy.c b/security/dummy.c
--- a/security/dummy.c	Sat Apr  3 19:38:42 2004
+++ b/security/dummy.c	Sat Apr  3 19:38:42 2004
@@ -25,6 +25,7 @@
 #include <linux/netlink.h>
 #include <net/sock.h>
 #include <linux/xattr.h>
+#include <linux/hugetlb.h>
 
 static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
 {
@@ -101,6 +102,14 @@
 	return 0;
 }
 
+/*
+ * Check that a process has enough memory to allocate a new virtual
+ * mapping. 0 means there is enough memory for the allocation to
+ * succeed and -ENOMEM implies there is not.
+ *
+ * We currently support three overcommit policies, which are set via the
+ * vm.overcommit_memory sysctl.  See Documentation/vm/overcommit-accounting
+ */
 static int dummy_vm_enough_memory(long pages)
 {
 	unsigned long free, allowed;
@@ -138,7 +147,8 @@
 		return -ENOMEM;
 	}
 
-	allowed = totalram_pages * sysctl_overcommit_ratio / 100;
+	allowed = (totalram_pages - hugetlb_total_pages())
+		* sysctl_overcommit_ratio / 100;
 	allowed += total_swap_pages;
 
 	if (atomic_read(&vm_committed_space) < allowed)
@@ -194,7 +204,8 @@
 	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 -Nru a/security/selinux/hooks.c b/security/selinux/hooks.c
--- a/security/selinux/hooks.c	Sat Apr  3 19:38:55 2004
+++ b/security/selinux/hooks.c	Sat Apr  3 19:38:55 2004
@@ -59,6 +59,7 @@
 #include <net/af_unix.h>	/* for Unix socket types */
 #include <linux/parser.h>
 #include <linux/nfs_mount.h>
+#include <linux/hugetlb.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -331,25 +332,24 @@
 
 	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) {
@@ -1454,7 +1454,7 @@
 
 static int selinux_quota_on(struct file *f)
 {
-	return file_has_perm(current, f, FILE__QUOTAON);;
+	return file_has_perm(current, f, FILE__QUOTAON);
 }
 
 static int selinux_syslog(int type)
@@ -1492,7 +1492,7 @@
  * succeed and -ENOMEM implies there is not.
  *
  * We currently support three overcommit policies, which are set via the
- * vm.overcommit_memory sysctl.  See Documentation/vm/overcommit-acounting
+ * vm.overcommit_memory sysctl.  See Documentation/vm/overcommit-accounting
  *
  * Strict overcommit modes added 2002 Feb 26 by Alan Cox.
  * Additional code 2002 Jul 20 by Robert Love.
@@ -1545,7 +1545,8 @@
 		return -ENOMEM;
 	}
 
-	allowed = totalram_pages * sysctl_overcommit_ratio / 100;
+	allowed = (totalram_pages - hugetlb_total_pages())
+		* sysctl_overcommit_ratio / 100;
 	allowed += total_swap_pages;
 
 	if (atomic_read(&vm_committed_space) < allowed)
@@ -1885,7 +1886,7 @@
 	*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 +1896,7 @@
 	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;
 	}
@@ -3041,6 +3041,8 @@
 		goto out;
 	
 	err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, NULL, &ad);
+	if (err)
+		goto out;
 
 	if (recv_perm) {
 		u32 port_sid;
diff -Nru a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
--- a/security/selinux/include/av_perm_to_string.h	Sat Apr  3 19:38:55 2004
+++ b/security/selinux/include/av_perm_to_string.h	Sat Apr  3 19:38:55 2004
@@ -84,6 +84,7 @@
    { 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 -Nru a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
--- a/security/selinux/include/av_permissions.h	Sat Apr  3 19:38:42 2004
+++ b/security/selinux/include/av_permissions.h	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/security/selinux/include/conditional.h b/security/selinux/include/conditional.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/security/selinux/include/conditional.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/security/selinux/include/security.h b/security/selinux/include/security.h
--- a/security/selinux/include/security.h	Sat Apr  3 19:38:41 2004
+++ b/security/selinux/include/security.h	Sat Apr  3 19:38:41 2004
@@ -2,7 +2,9 @@
  * Security server interface.
  *
  * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
+ *
  */
+
 #ifndef _SELINUX_SECURITY_H_
 #define _SELINUX_SECURITY_H_
 
@@ -13,12 +15,19 @@
 #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;
 #else
 #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);
diff -Nru a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
--- a/security/selinux/selinuxfs.c	Sat Apr  3 19:38:57 2004
+++ b/security/selinux/selinuxfs.c	Sat Apr  3 19:38:57 2004
@@ -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 @@
 	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 @@
 	.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 @@
 	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 @@
 	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 @@
 		[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 -Nru a/security/selinux/ss/Makefile b/security/selinux/ss/Makefile
--- a/security/selinux/ss/Makefile	Sat Apr  3 19:38:40 2004
+++ b/security/selinux/ss/Makefile	Sat Apr  3 19:38:40 2004
@@ -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 -Nru a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
--- a/security/selinux/ss/avtab.c	Sat Apr  3 19:38:54 2004
+++ b/security/selinux/ss/avtab.c	Sat Apr  3 19:38:54 2004
@@ -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 @@
 			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 @@
 	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 @@
 	       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 @@
 		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 -Nru a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
--- a/security/selinux/ss/avtab.h	Sat Apr  3 19:38:42 2004
+++ b/security/selinux/ss/avtab.h	Sat Apr  3 19:38:42 2004
@@ -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 @@
 #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,7 +67,16 @@
 			    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)
diff -Nru a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/security/selinux/ss/conditional.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/security/selinux/ss/conditional.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h
--- a/security/selinux/ss/mls.h	Sat Apr  3 19:38:42 2004
+++ b/security/selinux/ss/mls.h	Sat Apr  3 19:38:42 2004
@@ -48,12 +48,12 @@
 
 #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 -Nru a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
--- a/security/selinux/ss/policydb.c	Sat Apr  3 19:38:43 2004
+++ b/security/selinux/ss/policydb.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 	"classes",
 	"roles",
 	"types",
-	"users"
+	"users",
 	mls_symtab_names
+	"bools"
 };
 #endif
 
@@ -29,8 +43,9 @@
 	32,
 	16,
 	512,
-	128
+	128,
 	mls_symtab_sizes
+	16
 };
 
 /*
@@ -95,6 +110,10 @@
 	if (rc)
 		goto out_free_avtab;
 
+	rc = cond_policydb_init(p);
+	if (rc)
+		goto out_free_avtab;
+
 out:
 	return rc;
 
@@ -195,8 +214,9 @@
 	class_index,
 	role_index,
 	type_index,
-	user_index
+	user_index,
 	mls_index_f
+	cond_index_bool
 };
 
 /*
@@ -267,8 +287,8 @@
 {
 	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 @@
 		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 @@
 	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 @@
 		kfree(gtmp);
 	}
 
+	cond_policydb_destroy(p);
+
 	return;
 }
 
@@ -1040,8 +1068,9 @@
 	class_read,
 	role_read,
 	type_read,
-	user_read
+	user_read,
 	mls_read_f
+	cond_read_bool
 };
 
 #define mls_config(x) \
@@ -1057,7 +1086,7 @@
 	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 @@
 	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 @@
 		       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;
@@ -1165,6 +1207,12 @@
 	rc = avtab_read(&p->te_avtab, fp, config);
 	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) {
diff -Nru a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
--- a/security/selinux/ss/policydb.h	Sat Apr  3 19:38:54 2004
+++ b/security/selinux/ss/policydb.h	Sat Apr  3 19:38:54 2004
@@ -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 @@
 };
 #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 @@
 #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 @@
 #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 @@
 #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;
@@ -191,6 +213,13 @@
 
 	/* 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 -Nru a/security/selinux/ss/services.c b/security/selinux/ss/services.c
--- a/security/selinux/ss/services.c	Sat Apr  3 19:38:55 2004
+++ b/security/selinux/ss/services.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 			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 @@
 	 * 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 &&
@@ -573,6 +586,7 @@
 	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 @@
 	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 @@
 			return -EINVAL;
 		}
 		ss_initialized = 1;
+
 		LOAD_UNLOCK;
 		selinux_complete_init();
 		return 0;
@@ -1046,6 +1073,7 @@
 	memcpy(&policydb, &newpolicydb, sizeof policydb);
 	sidtab_set(&sidtab, &newsidtab);
 	seqno = ++latest_granting;
+
 	POLICY_WRUNLOCK;
 	LOAD_UNLOCK;
 
@@ -1424,6 +1452,119 @@
 		}
 	}
 
+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 -Nru a/sound/arm/Kconfig b/sound/arm/Kconfig
--- a/sound/arm/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/sound/arm/Kconfig	Sat Apr  3 19:38:55 2004
@@ -6,6 +6,7 @@
 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 -Nru a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c
--- a/sound/arm/sa11xx-uda1341.c	Sat Apr  3 19:38:41 2004
+++ b/sound/arm/sa11xx-uda1341.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 	 * 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 -Nru a/sound/core/Kconfig b/sound/core/Kconfig
--- a/sound/core/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/sound/core/Kconfig	Sat Apr  3 19:38:54 2004
@@ -3,9 +3,23 @@
 	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 @@
 	  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_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 -Nru a/sound/core/Makefile b/sound/core/Makefile
--- a/sound/core/Makefile	Sat Apr  3 19:38:45 2004
+++ b/sound/core/Makefile	Sat Apr  3 19:38:45 2004
@@ -15,97 +15,20 @@
 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 -Nru a/sound/core/init.c b/sound/core/init.c
--- a/sound/core/init.c	Sat Apr  3 19:38:41 2004
+++ b/sound/core/init.c	Sat Apr  3 19:38:41 2004
@@ -79,6 +79,7 @@
 			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 @@
 			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,8 @@
 	}
 	if (card->private_free)
 		card->private_free(card);
-	snd_info_free_entry(card->proc_id);
+	if (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 -Nru a/sound/core/ioctl32/timer32.c b/sound/core/ioctl32/timer32.c
--- a/sound/core/ioctl32/timer32.c	Sat Apr  3 19:38:44 2004
+++ b/sound/core/ioctl32/timer32.c	Sat Apr  3 19:38:44 2004
@@ -88,8 +88,18 @@
 	{ SNDRV_TIMER_IOCTL_INFO32, AP(timer_info) },
 	MAP_COMPAT(SNDRV_TIMER_IOCTL_PARAMS),
 	{ SNDRV_TIMER_IOCTL_STATUS32, AP(timer_status) },
+#if 0
+	/* ** FIXME **
+	 * The following four entries are disabled because they conflict
+	 * with the TCOC* definitions.
+	 * Unfortunately, the current ioctl32 wrapper uses a single
+	 * hash table for all devices.  Once when the wrapper is fixed
+	 * with the table based on devices, they'll be back again.
+	 */
 	MAP_COMPAT(SNDRV_TIMER_IOCTL_START),
 	MAP_COMPAT(SNDRV_TIMER_IOCTL_STOP),
 	MAP_COMPAT(SNDRV_TIMER_IOCTL_CONTINUE),
+	MAP_COMPAT(SNDRV_TIMER_IOCTL_PAUSE),
+#endif
 	{ 0 },
 };
diff -Nru a/sound/core/memalloc.c b/sound/core/memalloc.c
--- a/sound/core/memalloc.c	Sat Apr  3 19:38:56 2004
+++ b/sound/core/memalloc.c	Sat Apr  3 19:38:56 2004
@@ -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 @@
 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 @@
 #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 @@
  * 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 @@
 		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 @@
 	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 @@
 	}
 	if (! dmab->area)
 		return -ENOMEM;
-	dmab->bytes = size;
 	return 0;
 }
 
@@ -230,24 +496,17 @@
 	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);
 	}
@@ -396,394 +655,6 @@
 }
 
 
-/*
- *
- *  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 */
-
 
 /*
  * allocation of buffers for pre-defined devices
@@ -821,6 +692,17 @@
 	{ }, /* 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 @@
 		len += sprintf(page + len, " : type ");
 		switch (mem->dev.type) {
 		case SNDRV_DMA_TYPE_CONTINUOUS:
-			len += sprintf(page + len, "CONT [%x]", mem->dev.dev.flags);
-			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);
+			len += sprintf(page + len, "CONT [%p]", mem->dev.dev);
 			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]", sdev->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 @@
  * 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_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 -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c	Sat Apr  3 19:38:55 2004
+++ b/sound/core/oss/pcm_oss.c	Sat Apr  3 19:38:55 2004
@@ -133,6 +133,15 @@
 	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 @@
 
 	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 @@
 	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 @@
 	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 @@
 	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 -Nru a/sound/core/pcm.c b/sound/core/pcm.c
--- a/sound/core/pcm.c	Sat Apr  3 19:38:56 2004
+++ b/sound/core/pcm.c	Sat Apr  3 19:38:56 2004
@@ -327,8 +327,9 @@
 		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);
@@ -402,7 +403,7 @@
 	snd_pcm_str_t *pstr = (snd_pcm_str_t *)entry->private_data;
 	char line[64];
 	if (!snd_info_get_line(buffer, line, sizeof(line)))
-		pstr->xrun_debug = !!simple_strtoul(line, NULL, 10);
+		pstr->xrun_debug = simple_strtoul(line, NULL, 10);
 }
 #endif
 
@@ -1060,3 +1061,4 @@
 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 -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
--- a/sound/core/pcm_lib.c	Sat Apr  3 19:38:43 2004
+++ b/sound/core/pcm_lib.c	Sat Apr  3 19:38:43 2004
@@ -67,8 +67,11 @@
 			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;
@@ -164,7 +167,8 @@
 				   substream->pcm->card->number,
 				   substream->pcm->device,
 				   substream->stream ? 'c' : 'p');
-			dump_stack();
+			if (substream->pstr->xrun_debug > 1)
+				dump_stack();
 		}
 #endif
 		return -EPIPE;
@@ -191,8 +195,11 @@
 	if (delta > 0) {
 		if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
 #ifdef CONFIG_SND_DEBUG
-			if (runtime->periods > 1)
+			if (runtime->periods > 1 && substream->pstr->xrun_debug) {
 				snd_printd(KERN_ERR "Unexpected hw_pointer value [1] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
+				if (substream->pstr->xrun_debug > 1)
+					dump_stack();
+			}
 #endif
 			return 0;
 		}
@@ -229,8 +236,11 @@
 	if (delta > 0) {
 		if ((snd_pcm_uframes_t)delta < runtime->buffer_size / 2) {
 #ifdef CONFIG_SND_DEBUG
-			if (runtime->periods > 2)
+			if (runtime->periods > 2 && substream->pstr->xrun_debug) {
 				snd_printd(KERN_ERR "Unexpected hw_pointer value [2] (stream = %i, delta: -%ld, max jitter = %ld): wrong interrupt acknowledge?\n", substream->stream, (long) delta, runtime->buffer_size / 2);
+				if (substream->pstr->xrun_debug > 1)
+					dump_stack();
+			}
 #endif
 			return 0;
 		}
@@ -2659,20 +2669,6 @@
 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 -Nru a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c
--- a/sound/core/pcm_memory.c	Sat Apr  3 19:38:45 2004
+++ b/sound/core/pcm_memory.c	Sat Apr  3 19:38:45 2004
@@ -229,97 +229,71 @@
 }
 
 /**
- * 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
@@ -397,183 +371,6 @@
 	runtime->dma_private = NULL;
 	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
 
diff -Nru a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
--- a/sound/core/pcm_misc.c	Sat Apr  3 19:38:54 2004
+++ b/sound/core/pcm_misc.c	Sat Apr  3 19:38:54 2004
@@ -654,3 +654,35 @@
 	}
 	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 -Nru a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c
--- a/sound/core/pcm_timer.c	Sat Apr  3 19:38:56 2004
+++ b/sound/core/pcm_timer.c	Sat Apr  3 19:38:56 2004
@@ -32,9 +32,9 @@
  */
 
 /* Greatest common divisor */
-static int gcd(int a, int b)
+static unsigned long gcd(unsigned long a, unsigned long b)
 {
-	int r;
+	unsigned long r;
 	if (a < b) {
 		r = a;
 		a = b;
@@ -49,7 +49,7 @@
 
 void snd_pcm_timer_resolution_change(snd_pcm_substream_t *substream)
 {
-	unsigned int rate, mult, fsize, l;
+	unsigned long rate, mult, fsize, l;
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	
         mult = 1000000000;
@@ -67,7 +67,11 @@
 		mult /= 2;
 		rate /= 2;
 	}
-	snd_assert(rate != 0, return);
+	if (rate == 0) {
+		snd_printk(KERN_ERR "pcm timer resolution out of range (rate = %u, period_size = %lu)\n", runtime->rate, runtime->period_size);
+		runtime->timer_resolution = -1;
+		return;
+	}
 	runtime->timer_resolution = mult * fsize / rate;
 }
 
diff -Nru a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
--- a/sound/core/seq/oss/seq_oss_init.c	Sat Apr  3 19:38:41 2004
+++ b/sound/core/seq/oss/seq_oss_init.c	Sat Apr  3 19:38:41 2004
@@ -349,18 +349,11 @@
 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 -Nru a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c
--- a/sound/core/seq/oss/seq_oss_midi.c	Sat Apr  3 19:38:40 2004
+++ b/sound/core/seq/oss/seq_oss_midi.c	Sat Apr  3 19:38:40 2004
@@ -491,7 +491,7 @@
 			}
 		}
 	}
-	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 @@
 		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 @@
 		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 -Nru a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
--- a/sound/core/seq/oss/seq_oss_synth.c	Sat Apr  3 19:38:40 2004
+++ b/sound/core/seq/oss/seq_oss_synth.c	Sat Apr  3 19:38:40 2004
@@ -410,6 +410,8 @@
 		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 -Nru a/sound/core/seq/oss/seq_oss_synth.h b/sound/core/seq/oss/seq_oss_synth.h
--- a/sound/core/seq/oss/seq_oss_synth.h	Sat Apr  3 19:38:42 2004
+++ b/sound/core/seq/oss/seq_oss_synth.h	Sat Apr  3 19:38:42 2004
@@ -37,7 +37,7 @@
 void snd_seq_oss_synth_cleanup(seq_oss_devinfo_t *dp);
 
 void snd_seq_oss_synth_reset(seq_oss_devinfo_t *dp, int dev);
-int snd_seq_oss_synth_load_patch(seq_oss_devinfo_t *dp, int dev, int fmt, const char *buf, int p, int c);
+int snd_seq_oss_synth_load_patch(seq_oss_devinfo_t *dp, int dev, int fmt, const char __user *buf, int p, int c);
 int snd_seq_oss_synth_is_valid(seq_oss_devinfo_t *dp, int dev);
 int snd_seq_oss_synth_sysex(seq_oss_devinfo_t *dp, int dev, unsigned char *buf, snd_seq_event_t *ev);
 int snd_seq_oss_synth_addr(seq_oss_devinfo_t *dp, int dev, snd_seq_event_t *ev);
diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
--- a/sound/core/seq/seq_clientmgr.c	Sat Apr  3 19:38:41 2004
+++ b/sound/core/seq/seq_clientmgr.c	Sat Apr  3 19:38:41 2004
@@ -547,6 +547,36 @@
 
 
 /*
+ * 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 @@
 		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 @@
 	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 @@
 			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 -Nru a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c
--- a/sound/core/seq/seq_fifo.c	Sat Apr  3 19:38:43 2004
+++ b/sound/core/seq/seq_fifo.c	Sat Apr  3 19:38:43 2004
@@ -171,10 +171,12 @@
 {
 	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 @@
 			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 -Nru a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c
--- a/sound/core/seq/seq_memory.c	Sat Apr  3 19:38:41 2004
+++ b/sound/core/seq/seq_memory.c	Sat Apr  3 19:38:41 2004
@@ -220,12 +220,14 @@
 	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 @@
 	}
 	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 -Nru a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c
--- a/sound/core/seq/seq_midi.c	Sat Apr  3 19:38:55 2004
+++ b/sound/core/seq/seq_midi.c	Sat Apr  3 19:38:55 2004
@@ -257,17 +257,12 @@
 /* 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 @@
 	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 @@
 		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 -Nru a/sound/core/sgbuf.c b/sound/core/sgbuf.c
--- a/sound/core/sgbuf.c	Sat Apr  3 19:38:45 2004
+++ b/sound/core/sgbuf.c	Sat Apr  3 19:38:45 2004
@@ -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;
+
+	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;
+}
 
-/**
- * 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)
+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 @@
 	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 @@
 
 	/* 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++;
 	}
 
@@ -93,39 +109,4 @@
  _failed:
 	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 -Nru a/sound/drivers/Kconfig b/sound/drivers/Kconfig
--- a/sound/drivers/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/sound/drivers/Kconfig	Sat Apr  3 19:38:54 2004
@@ -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_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_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_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 -Nru a/sound/drivers/mpu401/Makefile b/sound/drivers/mpu401/Makefile
--- a/sound/drivers/mpu401/Makefile	Sat Apr  3 19:38:56 2004
+++ b/sound/drivers/mpu401/Makefile	Sat Apr  3 19:38:56 2004
@@ -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 -Nru a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
--- a/sound/drivers/mpu401/mpu401.c	Sat Apr  3 19:38:54 2004
+++ b/sound/drivers/mpu401/mpu401.c	Sat Apr  3 19:38:54 2004
@@ -2,6 +2,12 @@
  *  Driver for generic MPU-401 boards (UART mode only)
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
  *
+ *  ACPI PnP Copyright (c) 2004 by Clemens Ladisch <clemens@ladisch.de>
+ *  based on 8250_acpi.c
+ *  Copyright (c) 2002-2003 Matthew Wilcox for Hewlett-Packard
+ *  Copyright (C) 2004 Hewlett-Packard Co
+ *       Bjorn Helgaas <bjorn.helgaas@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
@@ -21,14 +27,17 @@
 
 #include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
+#ifdef CONFIG_ACPI_BUS
+#include <acpi/acpi_bus.h>
+#endif
 #include <sound/core.h>
 #include <sound/mpu401.h>
 #define SNDRV_GET_ID
 #include <sound/initval.h>
-#include <linux/delay.h>
+
+#ifdef CONFIG_ACPI_BUS
+#define USE_ACPI_PNP
+#endif
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("MPU-401 UART");
@@ -38,6 +47,9 @@
 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;	/* Enable this card */
+#ifdef USE_ACPI_PNP
+static int acpipnp[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
+#endif
 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* MPU-401 port number */
 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* MPU-401 IRQ */
 #ifdef CONFIG_X86_PC9800
@@ -53,6 +65,11 @@
 MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(enable, "Enable MPU-401 device.");
 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+#ifdef USE_ACPI_PNP
+MODULE_PARM(acpipnp, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(acpipnp, "ACPI PnP detection for MPU-401 device.");
+MODULE_PARM_SYNTAX(acpipnp, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
+#endif
 MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
 MODULE_PARM_DESC(port, "Port # for MPU-401 device.");
 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
@@ -65,25 +82,110 @@
 MODULE_PARM_SYNTAX(pc98ii, SNDRV_BOOLEAN_FALSE_DESC);
 #endif
 
-static snd_card_t *snd_mpu401_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
+#ifndef CONFIG_ACPI_BUS
+struct acpi_device;
+#endif
+
+static snd_card_t *snd_mpu401_legacy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
+static int cards;
+
+#ifdef USE_ACPI_PNP
+
+static int acpi_driver_registered;
+
+struct mpu401_resources {
+	unsigned long port;
+	int irq;
+};
+
+static acpi_status __devinit snd_mpu401_acpi_resource(struct acpi_resource *res,
+						      void *data)
+{
+	struct mpu401_resources *resources = (struct mpu401_resources *)data;
+
+	if (res->id == ACPI_RSTYPE_IRQ) {
+		if (res->data.irq.number_of_interrupts > 0) {
+#ifdef CONFIG_IA64
+			resources->irq = acpi_register_irq(res->data.irq.interrupts[0],
+							   res->data.irq.active_high_low,
+							   res->data.irq.edge_level);
+#else
+			resources->irq = res->data.irq.interrupts[0];
+#endif
+		}
+	} else if (res->id == ACPI_RSTYPE_IO) {
+		if (res->data.io.range_length >= 2) {
+			resources->port = res->data.io.min_base_address;
+		}
+	}
+	return AE_OK;
+}
+
+static int __devinit snd_mpu401_acpi_pnp(int dev, struct acpi_device *device)
+{
+	struct mpu401_resources res;
+	acpi_status status;
+
+	res.port = SNDRV_AUTO_PORT;
+	res.irq = SNDRV_AUTO_IRQ;
+	status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+				     snd_mpu401_acpi_resource, &res);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+	if (res.port == SNDRV_AUTO_PORT || res.irq == SNDRV_AUTO_IRQ) {
+		snd_printk(KERN_ERR "no port or irq in %s _CRS\n",
+			   acpi_device_bid(device));
+		return -ENODEV;
+	}
+	port[dev] = res.port;
+	irq[dev] = res.irq;
+	return 0;
+}
 
-static int __init snd_card_mpu401_probe(int dev)
+#endif /* USE_ACPI_PNP */
+
+static int __devinit snd_card_mpu401_probe(int dev, struct acpi_device *device)
 {
 	snd_card_t *card;
 	int err;
 
-	if (port[dev] == SNDRV_AUTO_PORT) {
-		snd_printk("specify port\n");
-		return -EINVAL;
-	}
-	if (irq[dev] == SNDRV_AUTO_IRQ) {
-		snd_printk("specify or disable IRQ port\n");
-		return -EINVAL;
+#ifdef USE_ACPI_PNP
+	if (!device) {
+#endif
+		if (port[dev] == SNDRV_AUTO_PORT) {
+			snd_printk(KERN_ERR "specify port\n");
+			return -EINVAL;
+		}
+		if (irq[dev] == SNDRV_AUTO_IRQ) {
+			snd_printk(KERN_ERR "specify or disable IRQ port\n");
+			return -EINVAL;
+		}
+#ifdef USE_ACPI_PNP
 	}
+#endif
+
+#ifdef USE_ACPI_PNP
+	if (device && (err = snd_mpu401_acpi_pnp(dev, device)) < 0)
+		return err;
+#endif
 
 	card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
 	if (card == NULL)
 		return -ENOMEM;
+	strcpy(card->driver, "MPU-401 UART");
+	strcpy(card->shortname, card->driver);
+	sprintf(card->longname, "%s at 0x%lx, ", card->shortname, port[dev]);
+	if (irq[dev] >= 0) {
+		sprintf(card->longname + strlen(card->longname), "IRQ %d", irq[dev]);
+	} else {
+		strcat(card->longname, "polled");
+	}
+#ifdef USE_ACPI_PNP
+	if (device) {
+		strcat(card->longname, ", bus id ");
+		strlcat(card->longname, acpi_device_bid(device), sizeof(card->longname));
+	}
+#endif
 	if (snd_mpu401_uart_new(card, 0,
 #ifdef CONFIG_X86_PC9800
 				pc98ii[dev] ? MPU401_HW_PC98II :
@@ -95,36 +197,93 @@
 		snd_card_free(card);
 		return -ENODEV;
 	}
-	strcpy(card->driver, "MPU-401 UART");
-	strcpy(card->shortname, card->driver);
-	sprintf(card->longname, "%s at 0x%lx, ", card->shortname, port[dev]);
-	if (irq[dev] >= 0) {
-		sprintf(card->longname + strlen(card->longname), "IRQ %d", irq[dev]);
-	} else {
-		strcat(card->longname, "polled");
-	}
 	if ((err = snd_card_register(card)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
-	snd_mpu401_cards[dev] = card;
+#ifdef USE_ACPI_PNP
+	if (device)
+		acpi_driver_data(device) = card;
+	else
+#endif
+		snd_mpu401_legacy_cards[dev] = card;
+	++cards;
 	return 0;
 }
 
+#ifdef USE_ACPI_PNP
+
+static int __devinit snd_mpu401_acpi_add(struct acpi_device *device)
+{
+	static int dev;
+	int err;
+
+	for ( ; dev < SNDRV_CARDS; ++dev) {
+		if (!enable[dev] || !acpipnp[dev])
+			continue;
+		err = snd_card_mpu401_probe(dev, device);
+		if (err < 0)
+			return err;
+		++dev;
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static int __devexit snd_mpu401_acpi_remove(struct acpi_device *device,
+					    int type)
+{
+	snd_card_t *card;
+
+	if (!device)
+		return -EINVAL;
+	card = (snd_card_t *)acpi_driver_data(device);
+	if (!card)
+		return -EINVAL;
+
+	snd_card_disconnect(card);
+	snd_card_free_in_thread(card);
+	acpi_driver_data(device) = NULL;
+	return 0;
+}
+
+static struct acpi_driver snd_mpu401_acpi_driver = {
+	.name = "MPU-401 Driver",
+	.class = "mpu401",
+	.ids = "PNPB006",
+	.ops = {
+		.add = snd_mpu401_acpi_add,
+		.remove = __devexit_p(snd_mpu401_acpi_remove),
+	},
+};
+
+#endif /* USE_ACPI_PNP */
+
 static int __init alsa_card_mpu401_init(void)
 {
-	int dev, cards = 0;
+	int dev;
 
+#ifdef USE_ACPI_PNP
+	if (acpi_bus_register_driver(&snd_mpu401_acpi_driver) >= 0)
+		acpi_driver_registered = 1;
+#endif
 	for (dev = 0; dev < SNDRV_CARDS; dev++) {
 		if (!enable[dev])
 			continue;
-		if (snd_card_mpu401_probe(dev) >= 0)
-			cards++;
+#ifdef USE_ACPI_PNP
+		if (acpipnp[dev] && acpi_driver_registered)
+			continue;
+#endif
+		snd_card_mpu401_probe(dev, NULL);
 	}
 	if (!cards) {
 #ifdef MODULE
 		printk(KERN_ERR "MPU-401 device not found or device busy\n");
 #endif
+#ifdef USE_ACPI_PNP
+		if (acpi_driver_registered)
+			acpi_bus_unregister_driver(&snd_mpu401_acpi_driver);
+#endif
 		return -ENODEV;
 	}
 	return 0;
@@ -134,8 +293,12 @@
 {
 	int idx;
 
+#ifdef USE_ACPI_PNP
+	if (acpi_driver_registered)
+		acpi_bus_unregister_driver(&snd_mpu401_acpi_driver);
+#endif
 	for (idx = 0; idx < SNDRV_CARDS; idx++)
-		snd_card_free(snd_mpu401_cards[idx]);
+		snd_card_free(snd_mpu401_legacy_cards[idx]);
 }
 
 module_init(alsa_card_mpu401_init)
@@ -143,22 +306,28 @@
 
 #ifndef MODULE
 
-/* format is: snd-mpu401=enable,index,id,port,irq */
+/* format is: snd-mpu401=enable,index,id,acpipnp[,pc98ii],port,irq */
 
 static int __init alsa_card_mpu401_setup(char *str)
 {
 	static unsigned __initdata nr_dev = 0;
+	int __attribute__ ((__unused__)) pnp = INT_MAX;
 
 	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,&pnp) == 2 &&
 #ifdef CONFIG_X86_PC9800
 	       get_option(&str,&pc98ii[nr_dev]) == 2 &&
 #endif
 	       get_option_long(&str,&port[nr_dev]) == 2 &&
 	       get_option(&str,&irq[nr_dev]) == 2);
+#ifdef USE_ACPI_PNP
+	if (pnp != INT_MAX)
+		acpipnp[nr_dev] = pnp;
+#endif
 	nr_dev++;
 	return 1;
 }
diff -Nru a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
--- a/sound/drivers/mpu401/mpu401_uart.c	Sat Apr  3 19:38:42 2004
+++ b/sound/drivers/mpu401/mpu401_uart.c	Sat Apr  3 19:38:42 2004
@@ -528,9 +528,9 @@
 	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 -Nru a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile
--- a/sound/drivers/opl3/Makefile	Sat Apr  3 19:38:40 2004
+++ b/sound/drivers/opl3/Makefile	Sat Apr  3 19:38:40 2004
@@ -9,37 +9,13 @@
 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
+#
+# 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_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)
-
-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 -Nru a/sound/drivers/opl4/Makefile b/sound/drivers/opl4/Makefile
--- a/sound/drivers/opl4/Makefile	Sat Apr  3 19:38:55 2004
+++ b/sound/drivers/opl4/Makefile	Sat Apr  3 19:38:55 2004
@@ -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 -Nru a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
--- a/sound/drivers/serial-u16550.c	Sat Apr  3 19:38:41 2004
+++ b/sound/drivers/serial-u16550.c	Sat Apr  3 19:38:41 2004
@@ -342,7 +342,7 @@
 	unsigned char c;
 
 	/* Do some vague tests for the presence of the uart */
-	if (io_base == 0) {
+	if (io_base == 0 || io_base == SNDRV_AUTO_PORT) {
 		return -ENODEV;	/* Not configured */
 	}
 
@@ -804,10 +804,9 @@
 		return err;
 	}
 
-	if (irq >= 0) {
+	if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
 		if (request_irq(irq, snd_uart16550_interrupt,
 				SA_INTERRUPT, "Serial MIDI", (void *) uart)) {
-			uart->irq = -1;
 			snd_printk("irq %d busy. Using Polling.\n", irq);
 		} else {
 			uart->irq = irq;
diff -Nru a/sound/drivers/vx/Makefile b/sound/drivers/vx/Makefile
--- a/sound/drivers/vx/Makefile	Sat Apr  3 19:38:41 2004
+++ b/sound/drivers/vx/Makefile	Sat Apr  3 19:38:41 2004
@@ -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 -Nru a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
--- a/sound/drivers/vx/vx_core.c	Sat Apr  3 19:38:55 2004
+++ b/sound/drivers/vx/vx_core.c	Sat Apr  3 19:38:55 2004
@@ -355,11 +355,12 @@
  */
 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(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 -Nru a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
--- a/sound/drivers/vx/vx_mixer.c	Sat Apr  3 19:38:42 2004
+++ b/sound/drivers/vx/vx_mixer.c	Sat Apr  3 19:38:42 2004
@@ -919,7 +919,7 @@
 	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 -Nru a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c
--- a/sound/drivers/vx/vx_pcm.c	Sat Apr  3 19:38:41 2004
+++ b/sound/drivers/vx/vx_pcm.c	Sat Apr  3 19:38:41 2004
@@ -561,7 +561,7 @@
 	.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 @@
 	.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 -Nru a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c
--- a/sound/i2c/cs8427.c	Sat Apr  3 19:38:40 2004
+++ b/sound/i2c/cs8427.c	Sat Apr  3 19:38:40 2004
@@ -50,6 +50,7 @@
 typedef struct {
 	unsigned char regmap[0x14];	/* map of first 1 + 13 registers */
 	unsigned int rate;
+	unsigned int reset_timeout;
 	cs8427_stream_t playback;
 	cs8427_stream_t capture;
 } cs8427_t;
@@ -163,6 +164,7 @@
 
 int snd_cs8427_create(snd_i2c_bus_t *bus,
 		      unsigned char addr,
+		      unsigned int reset_timeout,
 		      snd_i2c_device_t **r_cs8427)
 {
 	static unsigned char initvals1[] = {
@@ -256,6 +258,9 @@
 	snd_i2c_unlock(bus);
 
 	/* turn on run bit and rock'n'roll */
+	if (reset_timeout < 1)
+		reset_timeout = 1;
+	chip->reset_timeout = reset_timeout;
 	snd_cs8427_reset(device);
 
 #if 0	// it's nice for read tests
@@ -301,7 +306,7 @@
 	snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE, chip->regmap[CS8427_REG_CLOCKSOURCE]);
 	udelay(200);
 	snd_i2c_unlock(cs8427->bus);
-	end_time = jiffies + HZ / 2;
+	end_time = jiffies + chip->reset_timeout;
 	while (time_after_eq(end_time, jiffies)) {
 		snd_i2c_lock(cs8427->bus);
 		data = snd_cs8427_reg_read(cs8427, CS8427_REG_RECVERRORS);
@@ -309,7 +314,7 @@
 		if (!(data & CS8427_UNLOCK))
 			break;
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ/100);
+		schedule_timeout(1);
 	}
 	snd_i2c_lock(cs8427->bus);
 	chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK;
@@ -553,6 +558,7 @@
 			       SNDRV_CTL_EVENT_MASK_VALUE,
 			       &chip->playback.pcm_ctl->id);
 	reset = chip->rate != rate;
+	chip->rate = rate;
 	snd_i2c_unlock(cs8427->bus);
 	if (reset)
 		snd_cs8427_reset(cs8427);
diff -Nru a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile
--- a/sound/i2c/other/Makefile	Sat Apr  3 19:38:42 2004
+++ b/sound/i2c/other/Makefile	Sat Apr  3 19:38:42 2004
@@ -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 -Nru a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/i2c/other/ak4117.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/isa/Kconfig b/sound/isa/Kconfig
--- a/sound/isa/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/sound/isa/Kconfig	Sat Apr  3 19:38:55 2004
@@ -6,6 +6,9 @@
 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 -Nru a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
--- a/sound/isa/ad1816a/ad1816a_lib.c	Sat Apr  3 19:38:45 2004
+++ b/sound/isa/ad1816a/ad1816a_lib.c	Sat Apr  3 19:38:45 2004
@@ -684,7 +684,9 @@
 	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 -Nru a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
--- a/sound/isa/ad1848/ad1848_lib.c	Sat Apr  3 19:38:56 2004
+++ b/sound/isa/ad1848/ad1848_lib.c	Sat Apr  3 19:38:56 2004
@@ -1043,7 +1043,9 @@
 	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 -Nru a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
--- a/sound/isa/cmi8330.c	Sat Apr  3 19:38:41 2004
+++ b/sound/isa/cmi8330.c	Sat Apr  3 19:38:41 2004
@@ -438,7 +438,9 @@
 	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 -Nru a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
--- a/sound/isa/cs423x/cs4231_lib.c	Sat Apr  3 19:38:42 2004
+++ b/sound/isa/cs423x/cs4231_lib.c	Sat Apr  3 19:38:42 2004
@@ -1653,17 +1653,21 @@
 	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 -Nru a/sound/isa/dt019x.c b/sound/isa/dt019x.c
--- a/sound/isa/dt019x.c	Sat Apr  3 19:38:43 2004
+++ b/sound/isa/dt019x.c	Sat Apr  3 19:38:43 2004
@@ -143,7 +143,7 @@
 	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 @@
 		}
 		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:
@@ -296,8 +296,8 @@
 			return res;
 		dev++;
 		return 0;
-        }
-        return -ENODEV;
+	}
+	return -ENODEV;
 }
 
 static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard)
@@ -322,8 +322,10 @@
 	cards += pnp_register_card_driver(&dt019x_pnpc_driver);
 
 #ifdef MODULE
-	if (!cards)
+	if (!cards) {
+		pnp_unregister_card_driver(&dt019x_pnpc_driver);
 		snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n");
+	}
 #endif
 	return cards ? 0 : -ENODEV;
 }
diff -Nru a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c
--- a/sound/isa/es1688/es1688.c	Sat Apr  3 19:38:42 2004
+++ b/sound/isa/es1688/es1688.c	Sat Apr  3 19:38:42 2004
@@ -182,7 +182,7 @@
 static int __init alsa_card_es1688_init(void)
 {
 	static unsigned long possible_ports[] = {0x220, 0x240, 0x260, -1};
-	int dev, cards = 0;
+	int dev, cards = 0, i;
 
 	for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
 		if (port[dev] == SNDRV_AUTO_PORT)
@@ -190,7 +190,10 @@
 		if (snd_audiodrive_probe(dev) >= 0)
 			cards++;
 	}
-	cards += snd_legacy_auto_probe(possible_ports, snd_audiodrive_legacy_auto_probe);
+	i = snd_legacy_auto_probe(possible_ports, snd_audiodrive_legacy_auto_probe);
+	if (i > 0)
+		cards += i;
+
 	if (!cards) {
 #ifdef MODULE
 		printk(KERN_ERR "ESS AudioDrive ES1688 soundcard not found or device busy\n");
diff -Nru a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
--- a/sound/isa/es1688/es1688_lib.c	Sat Apr  3 19:38:44 2004
+++ b/sound/isa/es1688/es1688_lib.c	Sat Apr  3 19:38:44 2004
@@ -752,7 +752,9 @@
 	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 -Nru a/sound/isa/es18xx.c b/sound/isa/es18xx.c
--- a/sound/isa/es18xx.c	Sat Apr  3 19:38:43 2004
+++ b/sound/isa/es18xx.c	Sat Apr  3 19:38:43 2004
@@ -1598,7 +1598,10 @@
 	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;
@@ -2229,7 +2232,7 @@
 static int __init alsa_card_es18xx_init(void)
 {
 	static unsigned long possible_ports[] = {0x220, 0x240, 0x260, 0x280, -1};
-	int dev, cards = 0;
+	int dev, cards = 0, i;
 
 	/* legacy non-auto cards at first */
 	for (dev = 0; dev < SNDRV_CARDS; dev++) {
@@ -2243,10 +2246,16 @@
 			cards++;
 	}
 	/* legacy auto configured cards */
-	cards += snd_legacy_auto_probe(possible_ports, snd_audiodrive_probe_legacy_port);
+	i = snd_legacy_auto_probe(possible_ports, snd_audiodrive_probe_legacy_port);
+	if (i > 0)
+		cards += i;
+
 #ifdef CONFIG_PNP
 	/* ISA PnP cards at last */
-	cards += pnp_register_card_driver(&es18xx_pnpc_driver);
+	i = pnp_register_card_driver(&es18xx_pnpc_driver);
+	if (i > 0)
+		cards += i;
+
 #endif
 	if(!cards) {
 #ifdef CONFIG_PNP
diff -Nru a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c
--- a/sound/isa/gus/gus_pcm.c	Sat Apr  3 19:38:43 2004
+++ b/sound/isa/gus/gus_pcm.c	Sat Apr  3 19:38:43 2004
@@ -874,7 +874,9 @@
 	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 @@
 		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 -Nru a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c
--- a/sound/isa/gus/gusclassic.c	Sat Apr  3 19:38:57 2004
+++ b/sound/isa/gus/gusclassic.c	Sat Apr  3 19:38:57 2004
@@ -238,7 +238,7 @@
 static int __init alsa_card_gusclassic_init(void)
 {
 	static unsigned long possible_ports[] = {0x220, 0x230, 0x240, 0x250, 0x260, -1};
-	int dev, cards;
+	int dev, cards, i;
 
 	for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
 		if (port[dev] == SNDRV_AUTO_PORT)
@@ -246,7 +246,10 @@
 		if (snd_gusclassic_probe(dev) >= 0)
 			cards++;
 	}
-	cards += snd_legacy_auto_probe(possible_ports, snd_gusclassic_legacy_auto_probe);
+	i = snd_legacy_auto_probe(possible_ports, snd_gusclassic_legacy_auto_probe);
+	if (i > 0)
+		cards += i;
+
 	if (!cards) {
 #ifdef MODULE
 		printk(KERN_ERR "GUS Classic soundcard not found or device busy\n");
diff -Nru a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c
--- a/sound/isa/gus/gusextreme.c	Sat Apr  3 19:38:45 2004
+++ b/sound/isa/gus/gusextreme.c	Sat Apr  3 19:38:45 2004
@@ -220,17 +220,17 @@
 	xgf1_irq = gf1_irq[dev];
 	if (xgf1_irq == SNDRV_AUTO_IRQ) {
 		if ((xgf1_irq = snd_legacy_find_free_irq(possible_gf1_irqs)) < 0) {
-			snd_card_free(card);
 			snd_printk("unable to find a free IRQ for GF1\n");
-			return -EBUSY;
+			err = -EBUSY;
+			goto out;
 		}
 	}
 	xess_irq = irq[dev];
 	if (xess_irq == SNDRV_AUTO_IRQ) {
 		if ((xess_irq = snd_legacy_find_free_irq(possible_ess_irqs)) < 0) {
-			snd_card_free(card);
 			snd_printk("unable to find a free IRQ for ES1688\n");
-			return -EBUSY;
+			err = -EBUSY;
+			goto out;
 		}
 	}
 	if (mpu_port[dev] == SNDRV_AUTO_PORT)
@@ -241,26 +241,24 @@
 	xgf1_dma = dma1[dev];
 	if (xgf1_dma == SNDRV_AUTO_DMA) {
 		if ((xgf1_dma = snd_legacy_find_free_dma(possible_gf1_dmas)) < 0) {
-			snd_card_free(card);
 			snd_printk("unable to find a free DMA for GF1\n");
-			return -EBUSY;
+			err = -EBUSY;
+			goto out;
 		}
 	}
 	xess_dma = dma8[dev];
 	if (xess_dma == SNDRV_AUTO_DMA) {
 		if ((xess_dma = snd_legacy_find_free_dma(possible_ess_dmas)) < 0) {
-			snd_card_free(card);
 			snd_printk("unable to find a free DMA for ES1688\n");
-			return -EBUSY;
+			err = -EBUSY;
+			goto out;
 		}
 	}
 
 	if ((err = snd_es1688_create(card, port[dev], mpu_port[dev],
 				     xess_irq, xmpu_irq, xess_dma,
-				     ES1688_HW_1688, &es1688)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+				     ES1688_HW_1688, &es1688)) < 0)
+		goto out;
 	if (gf1_port[dev] < 0)
 		gf1_port[dev] = port[dev] + 0x20;
 	if ((err = snd_gus_create(card,
@@ -270,77 +268,65 @@
 				  -1,
 				  0, channels[dev],
 				  pcm_channels[dev], 0,
-				  &gus)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	if ((err = snd_gusextreme_detect(dev, card, gus, es1688)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+				  &gus)) < 0)
+		goto out;
+
+	if ((err = snd_gusextreme_detect(dev, card, gus, es1688)) < 0)
+		goto out;
+
 	snd_gusextreme_init(dev, gus);
-	if ((err = snd_gus_initialize(gus)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if ((err = snd_gus_initialize(gus)) < 0)
+		goto out;
+
 	if (!gus->ess_flag) {
 		snd_printdd("GUS Extreme soundcard was not detected at 0x%lx\n", gus->gf1.port);
-		snd_card_free(card);
-		return -ENODEV;
-	}
-	if ((err = snd_es1688_pcm(es1688, 0, NULL)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	if ((err = snd_es1688_mixer(es1688)) < 0) {
-		snd_card_free(card);
-		return err;
+		err = -ENODEV;
+		goto out;
 	}
+	if ((err = snd_es1688_pcm(es1688, 0, NULL)) < 0)
+		goto out;
+
+	if ((err = snd_es1688_mixer(es1688)) < 0)
+		goto out;
+
 	snd_component_add(card, "ES1688");
 	if (pcm_channels[dev] > 0) {
-		if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) {
-			snd_card_free(card);
-			return err;
-		}
-	}
-	if ((err = snd_gf1_new_mixer(gus)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
-	if ((err = snd_gusextreme_mixer(es1688)) < 0) {
-		snd_card_free(card);
-		return err;
+		if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0)
+			goto out;
 	}
+	if ((err = snd_gf1_new_mixer(gus)) < 0)
+		goto out;
+
+	if ((err = snd_gusextreme_mixer(es1688)) < 0)
+		goto out;
 
 	if (snd_opl3_create(card, es1688->port, es1688->port + 2,
 			    OPL3_HW_OPL3, 0, &opl3) < 0) {
 		printk(KERN_ERR "gusextreme: opl3 not detected at 0x%lx\n", es1688->port);
 	} else {
-		if ((err = snd_opl3_hwdep_new(opl3, 0, 2, NULL)) < 0) {
-			snd_card_free(card);
-			return err;
-		}
+		if ((err = snd_opl3_hwdep_new(opl3, 0, 2, NULL)) < 0)
+			goto out;
 	}
 
-	if (es1688->mpu_port >= 0x300) {
-		if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
+	if (es1688->mpu_port >= 0x300 &&
+	    (err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES1688,
 					       es1688->mpu_port, 0,
 					       xmpu_irq,
 					       SA_INTERRUPT,
-					       NULL)) < 0) {
-			snd_card_free(card);
-			return err;
-		}
-	}
+					       NULL)) < 0)
+		goto out;
 
 	sprintf(card->longname, "Gravis UltraSound Extreme at 0x%lx, irq %i&%i, dma %i&%i",
 		es1688->port, xgf1_irq, xess_irq, xgf1_dma, xess_dma);
-	if ((err = snd_card_register(card)) < 0) {
-		snd_card_free(card);
-		return err;
-	}
+	if ((err = snd_card_register(card)) < 0)
+		goto out;
+
 	snd_gusextreme_cards[dev] = card;
 	return 0;
+
+      out:
+	snd_card_free(card);
+	return err;
 }
 
 static int __init snd_gusextreme_legacy_auto_probe(unsigned long xport)
@@ -363,7 +349,7 @@
 static int __init alsa_card_gusextreme_init(void)
 {
 	static unsigned long possible_ports[] = {0x220, 0x240, 0x260, -1};
-	int dev, cards;
+	int dev, cards, i;
 
 	for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev] > 0; dev++) {
 		if (port[dev] == SNDRV_AUTO_PORT)
@@ -371,7 +357,10 @@
 		if (snd_gusextreme_probe(dev) >= 0)
 			cards++;
 	}
-	cards += snd_legacy_auto_probe(possible_ports, snd_gusextreme_legacy_auto_probe);
+	i = snd_legacy_auto_probe(possible_ports, snd_gusextreme_legacy_auto_probe);
+	if (i > 0)
+		cards += i;
+
 	if (!cards) {
 #ifdef MODULE
 		printk(KERN_ERR "GUS Extreme soundcard not found or device busy\n");
diff -Nru a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
--- a/sound/isa/gus/gusmax.c	Sat Apr  3 19:38:44 2004
+++ b/sound/isa/gus/gusmax.c	Sat Apr  3 19:38:44 2004
@@ -378,7 +378,7 @@
 static int __init alsa_card_gusmax_init(void)
 {
 	static unsigned long possible_ports[] = {0x220, 0x230, 0x240, 0x250, 0x260, -1};
-	int dev, cards;
+	int dev, cards, i;
 
 	for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev] > 0; dev++) {
 		if (port[dev] == SNDRV_AUTO_PORT)
@@ -386,7 +386,10 @@
 		if (snd_gusmax_probe(dev) >= 0)
 			cards++;
 	}
-	cards += snd_legacy_auto_probe(possible_ports, snd_gusmax_legacy_auto_probe);
+	i = snd_legacy_auto_probe(possible_ports, snd_gusmax_legacy_auto_probe);
+	if (i > 0)
+		cards += i;
+
 	if (!cards) {
 #ifdef MODULE
 		printk(KERN_ERR "GUS MAX soundcard not found or device busy\n");
diff -Nru a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
--- a/sound/isa/gus/interwave.c	Sat Apr  3 19:38:43 2004
+++ b/sound/isa/gus/interwave.c	Sat Apr  3 19:38:43 2004
@@ -929,7 +929,7 @@
 
 static int __init alsa_card_interwave_init(void)
 {
-	int cards = 0;
+	int cards = 0, i;
 	static long possible_ports[] = {0x210, 0x220, 0x230, 0x240, 0x250, 0x260, -1};
 	int dev;
 
@@ -949,10 +949,14 @@
 #endif
 	}
 	/* legacy auto configured cards */
-	cards += snd_legacy_auto_probe(possible_ports, snd_interwave_probe_legacy_port);
+	i = snd_legacy_auto_probe(possible_ports, snd_interwave_probe_legacy_port);
+	if (i > 0)
+		cards += i;
 #ifdef CONFIG_PNP
-        /* ISA PnP cards */
-        cards += pnp_register_card_driver(&interwave_pnpc_driver);
+	/* ISA PnP cards */
+	i = pnp_register_card_driver(&interwave_pnpc_driver);
+	if (i > 0)
+		cards += i;
 #endif
 
 	if (!cards) {
diff -Nru a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
--- a/sound/isa/opti9xx/opti92x-ad1848.c	Sat Apr  3 19:38:41 2004
+++ b/sound/isa/opti9xx/opti92x-ad1848.c	Sat Apr  3 19:38:41 2004
@@ -311,8 +311,12 @@
 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 @@
 
 	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 @@
 		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 @@
 		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 @@
 		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 @@
 	}
 #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 -Nru a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c
--- a/sound/isa/sb/es968.c	Sat Apr  3 19:38:43 2004
+++ b/sound/isa/sb/es968.c	Sat Apr  3 19:38:43 2004
@@ -203,8 +203,8 @@
 			return res;
 		dev++;
 		return 0;
-        }
-        return -ENODEV;
+	}
+	return -ENODEV;
 }
 
 static void __devexit snd_es968_pnp_remove(struct pnp_card_link * pcard)
@@ -225,15 +225,14 @@
 
 static int __init alsa_card_es968_init(void)
 {
-	int res = pnp_register_card_driver(&es968_pnpc_driver);
-	if (res == 0)
-	{
-		pnp_unregister_card_driver(&es968_pnpc_driver);
+	int cards = pnp_register_card_driver(&es968_pnpc_driver);
 #ifdef MODULE
+	if (cards == 0) {
+		pnp_unregister_card_driver(&es968_pnpc_driver);
 		snd_printk(KERN_ERR "no ES968 based soundcards found\n");
-#endif
 	}
-	return res < 0 ? res : 0;
+#endif
+	return cards ? 0 : -ENODEV;
 }
 
 static void __exit alsa_card_es968_exit(void)
diff -Nru a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c
--- a/sound/isa/sb/sb16.c	Sat Apr  3 19:38:55 2004
+++ b/sound/isa/sb/sb16.c	Sat Apr  3 19:38:55 2004
@@ -629,7 +629,7 @@
 
 static int __init alsa_card_sb16_init(void)
 {
-	int dev, cards = 0;
+	int dev, cards = 0, i;
 	static unsigned long possible_ports[] = {0x220, 0x240, 0x260, 0x280, -1};
 
 	/* legacy non-auto cards at first */
@@ -649,10 +649,15 @@
 #endif
 	}
 	/* legacy auto configured cards */
-	cards += snd_legacy_auto_probe(possible_ports, snd_sb16_probe_legacy_port);
+	i = snd_legacy_auto_probe(possible_ports, snd_sb16_probe_legacy_port);
+	if (i > 0)
+		cards += i;
+
 #ifdef CONFIG_PNP
 	/* PnP cards at last */
-	cards += pnp_register_card_driver(&sb16_pnpc_driver);
+	i = pnp_register_card_driver(&sb16_pnpc_driver);
+	if (i >0)
+		cards += i;
 #endif
 
 	if (!cards) {
diff -Nru a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
--- a/sound/isa/sb/sb16_main.c	Sat Apr  3 19:38:43 2004
+++ b/sound/isa/sb/sb16_main.c	Sat Apr  3 19:38:43 2004
@@ -881,7 +881,9 @@
 	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 -Nru a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
--- a/sound/isa/sb/sb8.c	Sat Apr  3 19:38:45 2004
+++ b/sound/isa/sb/sb8.c	Sat Apr  3 19:38:45 2004
@@ -199,7 +199,7 @@
 static int __init alsa_card_sb8_init(void)
 {
 	static unsigned long possible_ports[] = {0x220, 0x240, 0x260, -1};
-	int dev, cards;
+	int dev, cards, i;
 
 	for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
 		if (port[dev] == SNDRV_AUTO_PORT)
@@ -207,7 +207,10 @@
 		if (snd_sb8_probe(dev) >= 0)
 			cards++;
 	}
-	cards += snd_legacy_auto_probe(possible_ports, snd_card_sb8_legacy_auto_probe);
+	i = snd_legacy_auto_probe(possible_ports, snd_card_sb8_legacy_auto_probe);
+	if (i > 0)
+		cards += i;
+
 	if (!cards) {
 #ifdef MODULE
 		snd_printk(KERN_ERR "Sound Blaster soundcard not found or device busy\n");
diff -Nru a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c
--- a/sound/isa/sb/sb8_main.c	Sat Apr  3 19:38:43 2004
+++ b/sound/isa/sb/sb8_main.c	Sat Apr  3 19:38:43 2004
@@ -535,7 +535,9 @@
 	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 -Nru a/sound/isa/sscape.c b/sound/isa/sscape.c
--- a/sound/isa/sscape.c	Sat Apr  3 19:38:41 2004
+++ b/sound/isa/sscape.c	Sat Apr  3 19:38:41 2004
@@ -168,23 +168,20 @@
 }
 
 
-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 @@
 /*
  * 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 @@
                            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 @@
 		 * 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 -Nru a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
--- a/sound/isa/wavefront/wavefront_synth.c	Sat Apr  3 19:38:43 2004
+++ b/sound/isa/wavefront/wavefront_synth.c	Sat Apr  3 19:38:43 2004
@@ -1913,11 +1913,11 @@
 	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 @@
 	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 @@
 	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 @@
 			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 @@
 
 	}
 
-	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 -Nru a/sound/oss/Kconfig b/sound/oss/Kconfig
--- a/sound/oss/Kconfig	Sat Apr  3 19:38:55 2004
+++ b/sound/oss/Kconfig	Sat Apr  3 19:38:55 2004
@@ -1153,3 +1153,11 @@
 	tristate "AD1980 front/back switch plugin"
 	depends on SOUND_PRIME!=n
 
+config SOUND_SH_DAC_AUDIO
+	tristate "SuperH DAC audio support"
+	depends on SOUND_PRIME!=n && SOUND && CPU_SH3
+
+config SOUND_SH_DAC_AUDIO_CHANNEL
+	int "    DAC channel"
+	default "1"
+	depends on SOUND_SH_DAC_AUDIO
diff -Nru a/sound/oss/Makefile b/sound/oss/Makefile
--- a/sound/oss/Makefile	Sat Apr  3 19:38:42 2004
+++ b/sound/oss/Makefile	Sat Apr  3 19:38:42 2004
@@ -10,6 +10,7 @@
 
 # Please leave it as is, cause the link order is significant !
 
+obj-$(CONFIG_SOUND_SH_DAC_AUDIO)	+= sh_dac_audio.o
 obj-$(CONFIG_SOUND_HAL2)	+= hal2.o
 obj-$(CONFIG_SOUND_AEDSP16)	+= aedsp16.o
 obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
diff -Nru a/sound/oss/cmpci.c b/sound/oss/cmpci.c
--- a/sound/oss/cmpci.c	Sat Apr  3 19:38:43 2004
+++ b/sound/oss/cmpci.c	Sat Apr  3 19:38:43 2004
@@ -1462,7 +1462,9 @@
 
 static int cm_release_mixdev(struct inode *inode, struct file *file)
 {
-	struct cm_state *s = (struct cm_state *)file->private_data;
+	struct cm_state *s;
+
+	s = file->private_data;
 	
 	VALIDATE_STATE(s);
 	return 0;
diff -Nru a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
--- a/sound/oss/cs46xx.c	Sat Apr  3 19:38:40 2004
+++ b/sound/oss/cs46xx.c	Sat Apr  3 19:38:40 2004
@@ -3253,7 +3253,7 @@
 			
 		if (dmabuf->channel == NULL) {
 			kfree (card->states[0]);
-			card->states[0] = NULL;;
+			card->states[0] = NULL;
 			return -ENODEV;
 		}
 
@@ -3324,7 +3324,7 @@
 			
 		if (dmabuf->channel == NULL) {
 			kfree (card->states[1]);
-			card->states[1] = NULL;;
+			card->states[1] = NULL;
 			return -ENODEV;
 		}
 
diff -Nru a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
--- a/sound/oss/dmasound/dmasound_core.c	Sat Apr  3 19:38:41 2004
+++ b/sound/oss/dmasound/dmasound_core.c	Sat Apr  3 19:38:41 2004
@@ -1004,6 +1004,7 @@
 static int sq_fsync(struct file *filp, struct dentry *dentry)
 {
 	int rc = 0;
+	int timeout = 5;
 
 	write_sq.syncing |= 1;
 	sq_play();	/* there may be an incomplete frame waiting */
@@ -1016,6 +1017,12 @@
 			 * and clear the queue. */
 			sq_reset_output();
 			rc = -EINTR;
+			break;
+		}
+		if (!--timeout) {
+			printk(KERN_WARNING "dmasound: Timeout draining output\n");
+			sq_reset_output();
+			rc = -EIO;
 			break;
 		}
 	}
diff -Nru a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
--- a/sound/oss/i810_audio.c	Sat Apr  3 19:38:54 2004
+++ b/sound/oss/i810_audio.c	Sat Apr  3 19:38:54 2004
@@ -2471,7 +2471,7 @@
 	if(file->f_mode & FMODE_READ) {
 		if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) {
 			kfree (card->states[i]);
-			card->states[i] = NULL;;
+			card->states[i] = NULL;
 			return -EBUSY;
 		}
 		dmabuf->trigger |= PCM_ENABLE_INPUT;
@@ -2483,7 +2483,7 @@
 			if(file->f_mode & FMODE_READ)
 				card->free_pcm_channel(card,dmabuf->read_channel->num);
 			kfree (card->states[i]);
-			card->states[i] = NULL;;
+			card->states[i] = NULL;
 			return -EBUSY;
 		}
 		/* Initialize to 8kHz?  What if we don't support 8kHz? */
diff -Nru a/sound/oss/nec_vrc5477.c b/sound/oss/nec_vrc5477.c
--- a/sound/oss/nec_vrc5477.c	Sat Apr  3 19:38:54 2004
+++ b/sound/oss/nec_vrc5477.c	Sat Apr  3 19:38:54 2004
@@ -293,7 +293,7 @@
 
 	spin_unlock_irqrestore(&s->lock, flags);
 
-	return result & 0xffff;;
+	return result & 0xffff;
 }
 
 
diff -Nru a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c
--- a/sound/oss/nm256_audio.c	Sat Apr  3 19:38:43 2004
+++ b/sound/oss/nm256_audio.c	Sat Apr  3 19:38:43 2004
@@ -22,6 +22,7 @@
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pm.h>
 #include <linux/delay.h>
@@ -450,9 +451,6 @@
     }
 }
 
-/* Ultra cheez-whiz.  But I'm too lazy to grep headers. */
-#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
-
 /* 
  * Read the last-recorded block from the ring buffer, copy it into the
  * saved buffer pointer, and invoke DMAuf_inputintr() with the recording
@@ -480,7 +478,7 @@
 	/* If we wrapped around, copy everything from the start of our
 	   recording buffer to the end of the buffer. */
 	if (currptr < card->curRecPos) {
-	    u32 amt = MIN (ringsize - card->curRecPos, amtToRead);
+	    u32 amt = min (ringsize - card->curRecPos, amtToRead);
 
 	    nm256_readBuffer8 (card, card->recBuf, 1,
 				 card->abuf2 + card->curRecPos,
@@ -493,7 +491,7 @@
 	}
 
 	if ((card->curRecPos < currptr) && (amtToRead > 0)) {
-	    u32 amt = MIN (currptr - card->curRecPos, amtToRead);
+	    u32 amt = min (currptr - card->curRecPos, amtToRead);
 	    nm256_readBuffer8 (card, card->recBuf, 1,
 				 card->abuf2 + card->curRecPos, amt);
 	    card->curRecPos = ((card->curRecPos + amt) % ringsize);
@@ -503,9 +501,8 @@
 	DMAbuf_inputintr (card->dev_for_record);
     }
 }
-#undef MIN
 
-/* 
+/*
  * Initialize the hardware. 
  */
 static void
diff -Nru a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
--- a/sound/oss/opl3sa2.c	Sat Apr  3 19:38:40 2004
+++ b/sound/oss/opl3sa2.c	Sat Apr  3 19:38:40 2004
@@ -160,7 +160,6 @@
 } opl3sa2_state_t;
 static opl3sa2_state_t opl3sa2_state[OPL3SA2_CARDS_MAX];
 
-static spinlock_t opl3sa2_lock = SPIN_LOCK_UNLOCKED;
 	
 
 /* Our parameters */
@@ -853,6 +852,8 @@
 /* End of component functions */
 
 #ifdef CONFIG_PM
+static spinlock_t opl3sa2_lock = SPIN_LOCK_UNLOCKED;
+
 /* Power Management support functions */
 static int opl3sa2_suspend(struct pm_dev *pdev, unsigned int pm_mode)
 {
diff -Nru a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c
--- a/sound/oss/rme96xx.c	Sat Apr  3 19:38:42 2004
+++ b/sound/oss/rme96xx.c	Sat Apr  3 19:38:42 2004
@@ -1320,7 +1320,7 @@
 		count = rme96xx_getispace(dma,val);
 
 		abinfo.fragsize = (s->fragsize*dma->inchannels)>>dma->formatshift;
-                abinfo.bytes = (count*dma->inchannels)>>dma->formatshift;;
+                abinfo.bytes = (count*dma->inchannels)>>dma->formatshift;
                 abinfo.fragstotal = 2;
                 abinfo.fragments = count > s->fragsize; 
 		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
@@ -1348,7 +1348,7 @@
 			return -EINVAL;
 		val = rme96xx_gethwptr(dma->s,0);
 		spin_lock_irqsave(&s->lock,flags);
-                cinfo.bytes = s->fragsize<<1;;
+                cinfo.bytes = s->fragsize<<1;
 		count = val - dma->readptr;
 		if (count < 0)
 			count += s->fragsize<<1;
@@ -1368,7 +1368,7 @@
 			return -EINVAL;
 		val = rme96xx_gethwptr(dma->s,0);
 		spin_lock_irqsave(&s->lock,flags);
-                cinfo.bytes = s->fragsize<<1;;
+                cinfo.bytes = s->fragsize<<1;
 		count = val - dma->writeptr;
 		if (count < 0)
 			count += s->fragsize<<1;
diff -Nru a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/oss/sh_dac_audio.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,325 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/linkage.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <linux/interrupt.h>
+
+#include <asm/cpu/dac.h>
+
+#ifdef MACH_HP600
+#include <asm/hp6xx/hp6xx.h>
+#include <asm/hd64461/hd64461.h>
+#endif
+
+#define MODNAME "sh_dac_audio"
+
+#define TMU_TOCR_INIT	0x00
+
+#define TMU1_TCR_INIT	0x0020	/* Clock/4, rising edge; interrupt on */
+#define TMU1_TSTR_INIT  0x02	/* Bit to turn on TMU1 */
+
+#define TMU_TSTR	0xfffffe92
+#define TMU1_TCOR	0xfffffea0
+#define TMU1_TCNT	0xfffffea4
+#define TMU1_TCR	0xfffffea8
+
+#define BUFFER_SIZE 48000
+
+static int rate;
+static int empty;
+static char *data_buffer, *buffer_begin, *buffer_end;
+static int in_use, device_major;
+
+static void dac_audio_start_timer(void)
+{
+	u8 tstr;
+
+	tstr = ctrl_inb(TMU_TSTR);
+	tstr |= TMU1_TSTR_INIT;
+	ctrl_outb(tstr, TMU_TSTR);
+}
+
+static void dac_audio_stop_timer(void)
+{
+	u8 tstr;
+
+	tstr = ctrl_inb(TMU_TSTR);
+	tstr &= ~TMU1_TSTR_INIT;
+	ctrl_outb(tstr, TMU_TSTR);
+}
+
+static void dac_audio_reset(void)
+{
+	dac_audio_stop_timer();
+	buffer_begin = buffer_end = data_buffer;
+	empty = 1;
+}
+
+static void dac_audio_sync(void)
+{
+	while (!empty)
+		schedule();
+}
+
+static void dac_audio_start(void)
+{
+#ifdef MACH_HP600
+	u16 v;
+	v = inw(HD64461_GPADR);
+	v &= ~HD64461_GPADR_SPEAKER;
+	outw(v, HD64461_GPADR);
+#endif
+	sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
+	ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
+}
+static void dac_audio_stop(void)
+{
+#ifdef MACH_HP600
+	u16 v;
+#endif
+	dac_audio_stop_timer();
+#ifdef MACH_HP600
+	v = inw(HD64461_GPADR);
+	v |= HD64461_GPADR_SPEAKER;
+	outw(v, HD64461_GPADR);
+#endif
+	sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
+}
+
+static void dac_audio_set_rate(void)
+{
+	unsigned long interval;
+
+	interval = (current_cpu_data.module_clock / 4) / rate;
+	ctrl_outl(interval, TMU1_TCOR);
+	ctrl_outl(interval, TMU1_TCNT);
+}
+
+static int dac_audio_ioctl(struct inode *inode, struct file *file,
+			   unsigned int cmd, unsigned long arg)
+{
+	int val;
+
+	switch (cmd) {
+	case OSS_GETVERSION:
+		return put_user(SOUND_VERSION, (int *)arg);
+
+	case SNDCTL_DSP_SYNC:
+		dac_audio_sync();
+		return 0;
+
+	case SNDCTL_DSP_RESET:
+		dac_audio_reset();
+		return 0;
+
+	case SNDCTL_DSP_GETFMTS:
+		return put_user(AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_SETFMT:
+		return put_user(AFMT_U8, (int *)arg);
+
+	case SNDCTL_DSP_NONBLOCK:
+		file->f_flags |= O_NONBLOCK;
+		return 0;
+
+	case SNDCTL_DSP_GETCAPS:
+		return 0;
+
+	case SOUND_PCM_WRITE_RATE:
+		val = *(int *)arg;
+		if (val > 0) {
+			rate = val;
+			dac_audio_set_rate();
+		}
+		return put_user(rate, (int *)arg);
+
+	case SNDCTL_DSP_STEREO:
+		return put_user(0, (int *)arg);
+
+	case SOUND_PCM_WRITE_CHANNELS:
+		return put_user(1, (int *)arg);
+
+	case SNDCTL_DSP_SETDUPLEX:
+		return -EINVAL;
+
+	case SNDCTL_DSP_PROFILE:
+		return -EINVAL;
+
+	case SNDCTL_DSP_GETBLKSIZE:
+		return put_user(BUFFER_SIZE, (int *)arg);
+
+	case SNDCTL_DSP_SETFRAGMENT:
+		return 0;
+
+	default:
+		printk(KERN_ERR "sh_dac_audio: unimplemented ioctl=0x%x\n",
+		       cmd);
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count,
+			       loff_t * ppos)
+{
+	int free;
+	int nbytes;
+
+	if (count < 0)
+		return -EINVAL;
+
+	if (!count) {
+		dac_audio_sync();
+		return 0;
+	}
+
+	free = buffer_begin - buffer_end;
+
+	if (free < 0)
+		free += BUFFER_SIZE;
+	if ((free == 0) && (empty))
+		free = BUFFER_SIZE;
+	if (count > free)
+		count = free;
+	if (buffer_begin > buffer_end) {
+		if (copy_from_user((void *)buffer_end, buf, count))
+			return -EFAULT;
+
+		buffer_end += count;
+	} else {
+		nbytes = data_buffer + BUFFER_SIZE - buffer_end;
+		if (nbytes > count) {
+			if (copy_from_user((void *)buffer_end, buf, count))
+				return -EFAULT;
+			buffer_end += count;
+		} else {
+			if (copy_from_user((void *)buffer_end, buf, nbytes))
+				return -EFAULT;
+			if (copy_from_user
+			    ((void *)data_buffer, buf + nbytes, count - nbytes))
+				return -EFAULT;
+			buffer_end = data_buffer + count - nbytes;
+		}
+	}
+
+	if (empty) {
+		empty = 0;
+		dac_audio_start_timer();
+	}
+
+	return count;
+}
+
+static ssize_t dac_audio_read(struct file *file, char *buf, size_t count,
+			      loff_t * ppos)
+{
+	return -EINVAL;
+}
+
+static int dac_audio_open(struct inode *inode, struct file *file)
+{
+	if (file->f_mode & FMODE_READ)
+		return -ENODEV;
+	if (in_use)
+		return -EBUSY;
+
+	in_use = 1;
+
+	dac_audio_start();
+
+	return 0;
+}
+
+static int dac_audio_release(struct inode *inode, struct file *file)
+{
+	dac_audio_sync();
+	dac_audio_stop();
+	in_use = 0;
+
+	return 0;
+}
+
+struct file_operations dac_audio_fops = {
+      .read =		dac_audio_read,
+      .write =	dac_audio_write,
+      .ioctl =	dac_audio_ioctl,
+      .open =		dac_audio_open,
+      .release =	dac_audio_release,
+};
+
+static irqreturn_t timer1_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+	unsigned long timer_status;
+
+	timer_status = ctrl_inw(TMU1_TCR);
+	timer_status &= ~0x100;
+	ctrl_outw(timer_status, TMU1_TCR);
+
+	if (!empty) {
+		sh_dac_output(*buffer_begin, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
+		buffer_begin++;
+
+		if (buffer_begin == data_buffer + BUFFER_SIZE)
+			buffer_begin = data_buffer;
+		if (buffer_begin == buffer_end) {
+			empty = 1;
+			dac_audio_stop_timer();
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int __init dac_audio_init(void)
+{
+	int retval;
+
+	if ((device_major = register_sound_dsp(&dac_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "Cannot register dsp device");
+		return device_major;
+	}
+
+	in_use = 0;
+
+	data_buffer = (char *)kmalloc(BUFFER_SIZE, GFP_KERNEL);
+	if (data_buffer == NULL)
+		return -ENOMEM;
+
+	dac_audio_reset();
+	rate = 8000;
+	dac_audio_set_rate();
+
+	retval =
+	    request_irq(TIMER1_IRQ, timer1_interrupt, SA_INTERRUPT, MODNAME, 0);
+	if (retval < 0) {
+		printk(KERN_ERR "sh_dac_audio: IRQ %d request failed\n",
+		       TIMER1_IRQ);
+		return retval;
+	}
+
+	return 0;
+}
+
+static void __exit dac_audio_exit(void)
+{
+	free_irq(TIMER1_IRQ, 0);
+
+	unregister_sound_dsp(device_major);
+	kfree((void *)data_buffer);
+}
+
+module_init(dac_audio_init);
+module_exit(dac_audio_exit);
+
+MODULE_AUTHOR("Andriy Skulysh, askulysh@image.kiev.ua");
+MODULE_DESCRIPTION("SH DAC sound driver");
+MODULE_LICENSE("GPL");
diff -Nru a/sound/oss/soundcard.c b/sound/oss/soundcard.c
--- a/sound/oss/soundcard.c	Sat Apr  3 19:38:43 2004
+++ b/sound/oss/soundcard.c	Sat Apr  3 19:38:43 2004
@@ -136,10 +136,6 @@
 	return 0;
 }
 
-#ifndef MIN
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
 /* 4K page size but our output routines use some slack for overruns */
 #define PROC_BLOCK_SIZE (3*1024)
 
@@ -710,7 +706,7 @@
 
 void sound_stop_timer(void)
 {
-	del_timer(&seq_timer);;
+	del_timer(&seq_timer);
 }
 
 void conf_printf(char *name, struct address_info *hw_config)
diff -Nru a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c
--- a/sound/oss/sys_timer.c	Sat Apr  3 19:38:43 2004
+++ b/sound/oss/sys_timer.c	Sat Apr  3 19:38:43 2004
@@ -116,7 +116,7 @@
 def_tmr_close(int dev)
 {
 	opened = tmr_running = 0;
-	del_timer(&def_tmr);;
+	del_timer(&def_tmr);
 }
 
 static int
diff -Nru a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
--- a/sound/oss/via82cxxx_audio.c	Sat Apr  3 19:38:42 2004
+++ b/sound/oss/via82cxxx_audio.c	Sat Apr  3 19:38:42 2004
@@ -3411,11 +3411,17 @@
 	rc = pci_enable_device (pdev);
 	if (rc)
 		goto err_out;
-		
 
 	rc = pci_request_regions (pdev, "via82cxxx_audio");
 	if (rc)
 		goto err_out_disable;
+
+	rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+	if (rc)
+		goto err_out_res;
+	rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+	if (rc)
+		goto err_out_res;
 
 	card = kmalloc (sizeof (*card), GFP_KERNEL);
 	if (!card) {
diff -Nru a/sound/oss/wavfront.c b/sound/oss/wavfront.c
--- a/sound/oss/wavfront.c	Sat Apr  3 19:38:44 2004
+++ b/sound/oss/wavfront.c	Sat Apr  3 19:38:44 2004
@@ -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 @@
 }
 
 #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 @@
 	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 @@
 	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 @@
 			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 @@
 
 	}
 
-	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 -Nru a/sound/parisc/Kconfig b/sound/parisc/Kconfig
--- a/sound/parisc/Kconfig	Sat Apr  3 19:38:44 2004
+++ b/sound/parisc/Kconfig	Sat Apr  3 19:38:44 2004
@@ -6,6 +6,7 @@
 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 -Nru a/sound/parisc/harmony.c b/sound/parisc/harmony.c
--- a/sound/parisc/harmony.c	Sat Apr  3 19:38:43 2004
+++ b/sound/parisc/harmony.c	Sat Apr  3 19:38:43 2004
@@ -205,6 +205,7 @@
 	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 @@
  * 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 @@
 		}
 	}
 	snd_harmony_enable_interrupts(harmony);
+
+	return IRQ_HANDLED;
 }
 
 /* 
@@ -541,7 +544,7 @@
 		case SNDRV_PCM_TRIGGER_STOP:
 			if (harmony->cap_stopped) 
 				return -EBUSY;
-			harmony->cap_stopped = 1;;
+			harmony->cap_stopped = 1;
 			snd_harmony_disable_interrupts(harmony);
 			break;
 		case SNDRV_PCM_TRIGGER_START:
@@ -844,22 +847,27 @@
 	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 -Nru a/sound/pci/Kconfig b/sound/pci/Kconfig
--- a/sound/pci/Kconfig	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/Kconfig	Sat Apr  3 19:38:42 2004
@@ -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_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_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_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_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_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_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_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_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_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_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_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_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 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_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_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 -Nru a/sound/pci/Makefile b/sound/pci/Makefile
--- a/sound/pci/Makefile	Sat Apr  3 19:38:40 2004
+++ b/sound/pci/Makefile	Sat Apr  3 19:38:40 2004
@@ -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-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 @@
 
 # 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_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 -Nru a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile
--- a/sound/pci/ac97/Makefile	Sat Apr  3 19:38:44 2004
+++ b/sound/pci/ac97/Makefile	Sat Apr  3 19:38:44 2004
@@ -7,21 +7,7 @@
 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 -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
--- a/sound/pci/ac97/ac97_codec.c	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/ac97/ac97_codec.c	Sat Apr  3 19:38:42 2004
@@ -100,13 +100,12 @@
 { 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 },
@@ -172,6 +171,7 @@
 { 0x83847650, 0xffffffff, "STAC9750/51",	NULL,		NULL },	// patch?
 { 0x83847652, 0xffffffff, "STAC9752/53",	NULL,		NULL }, // patch?
 { 0x83847656, 0xffffffff, "STAC9756/57",	patch_sigmatel_stac9756,	NULL },
+{ 0x83847658, 0xffffffff, "STAC9758/59",	patch_sigmatel_stac9758,	NULL },
 { 0x83847666, 0xffffffff, "STAC9766/67",	NULL,		NULL }, // patch?
 { 0, 	      0,	  NULL,			NULL,		NULL }
 };
@@ -273,6 +273,11 @@
 {
 	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);
 }
 
@@ -391,11 +396,14 @@
 		ac97->spec.ad18xx.pcmreg[codec] = new;
 		spin_unlock(&ac97->reg_lock);
 		/* select single codec */
-		ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
+		ac97->bus->write(ac97, AC97_AD_SERIAL_CFG,
+				 (ac97->regs[AC97_AD_SERIAL_CFG] & ~0x7000) |
+				 ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
 		/* update PCM bits */
 		ac97->bus->write(ac97, AC97_PCM, new);
 		/* select all codecs */
-		ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+		ac97->bus->write(ac97, AC97_AD_SERIAL_CFG,
+				 ac97->regs[AC97_AD_SERIAL_CFG] | 0x7000);
 	} else
 		spin_unlock(&ac97->reg_lock);
 	up(&ac97->spec.ad18xx.mutex);
@@ -688,7 +696,7 @@
 };
 
 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 +1534,40 @@
 	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 +1876,8 @@
 	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 +1894,16 @@
 						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 +1947,15 @@
 			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 +2010,18 @@
 	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:
 
@@ -2009,11 +2035,12 @@
 			if (! ac97->spec.ad18xx.id[codec])
 				continue;
 			/* select single codec */
-			ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
+			snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+					     ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
 			ac97->bus->write(ac97, AC97_AD_CODEC_CFG, ac97->spec.ad18xx.codec_cfg[codec]);
 		}
 		/* select all codecs */
-		ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+		snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
 	}
 
 	/* restore ac97 status */
@@ -2032,12 +2059,13 @@
 						if (! ac97->spec.ad18xx.id[codec])
 							continue;
 						/* select single codec */
-						ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
+						snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+								     ac97->spec.ad18xx.unchained[codec] | ac97->spec.ad18xx.chained[codec]);
 						/* update PCM bits */
 						ac97->bus->write(ac97, AC97_PCM, ac97->spec.ad18xx.pcmreg[codec]);
 					}
 					/* select all codecs */
-					ac97->bus->write(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+					snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
 					continue;
 				} else if (i == AC97_AD_TEST ||
 					   i == AC97_AD_CODEC_CFG ||
@@ -2112,6 +2140,8 @@
 {
 	/* 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 +2164,30 @@
 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 +2201,8 @@
 		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 -Nru a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
--- a/sound/pci/ac97/ac97_patch.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/ac97/ac97_patch.c	Sat Apr  3 19:38:55 2004
@@ -292,6 +292,9 @@
 	return 0;
 }
 
+/*
+ * Tritech codec
+ */
 int patch_tritech_tr28028(ac97_t * ac97)
 {
 	snd_ac97_write_cache(ac97, 0x26, 0x0300);
@@ -301,6 +304,9 @@
 	return 0;
 }
 
+/*
+ * Sigmatel STAC97xx codecs
+ */
 static int patch_sigmatel_stac9700_3d(ac97_t * ac97)
 {
 	snd_kcontrol_t *kctl;
@@ -441,6 +447,24 @@
 	return 0;
 }
 
+int patch_sigmatel_stac9758(ac97_t * ac97)
+{
+	// patch for SigmaTel
+	ac97->build_ops = &patch_sigmatel_stac9700_ops;
+	// turn on stereo speaker, headphone and line-out
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_OUTSEL, 0x9040);
+	// headphone select and boost
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_IOMISC, 0x2102);
+	// enable mic
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_INSEL, 0x0203);
+	// enable stereo mic
+	snd_ac97_write_cache(ac97, AC97_SIGMATEL_VARIOUS, 0x0001);
+	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 +523,9 @@
 	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,10 +557,16 @@
 	return 0;
 }
 
+/*
+ * Analog Device AD18xx, AD19xx codecs
+ */
 int patch_ad1819(ac97_t * ac97)
 {
+	unsigned short scfg;
+
 	// patch for Analog Devices
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000); /* select all codecs */
+	scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
+	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x7000); /* select all codecs */
 	return 0;
 }
 
@@ -542,7 +575,7 @@
 	unsigned short val;
 
 	// test for unchained codec
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, mask);
+	snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, mask);
 	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0000);	/* ID0C, ID1C, SDIE = off */
 	val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
 	if ((val & 0xff40) != 0x5340)
@@ -558,7 +591,7 @@
 	static int cfg_bits[3] = { 1<<12, 1<<14, 1<<13 };
 	unsigned short val;
 	
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, cfg_bits[idx]);
+	snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, cfg_bits[idx]);
 	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0004);	// SDIE
 	val = snd_ac97_read(ac97, AC97_VENDOR_ID2);
 	if ((val & 0xff40) != 0x5340)
@@ -581,7 +614,8 @@
 	if (cidx1 < 0 && cidx2 < 0)
 		return;
 	// test for chained codecs
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[unchained_idx]);
+	snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+			     ac97->spec.ad18xx.unchained[unchained_idx]);
 	snd_ac97_write_cache(ac97, AC97_AD_CODEC_CFG, 0x0002);		// ID1C
 	ac97->spec.ad18xx.codec_cfg[unchained_idx] = 0x0002;
 	if (cidx1 >= 0) {
@@ -604,10 +638,13 @@
 	
 	// patch for Analog Devices
 	unsigned short codecs[3];
+	unsigned short val;
 	int idx, num;
 
 	init_MUTEX(&ac97->spec.ad18xx.mutex);
 
+	val = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG);
+	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, val);
 	codecs[0] = patch_ad1881_unchained(ac97, 0, (1<<12));
 	codecs[1] = patch_ad1881_unchained(ac97, 1, (1<<14));
 	codecs[2] = patch_ad1881_unchained(ac97, 2, (1<<13));
@@ -629,7 +666,7 @@
 
       __end:
 	/* select all codecs */
-	snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+	snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
 	/* check if only one codec is present */
 	for (idx = num = 0; idx < 3; idx++)
 		if (ac97->spec.ad18xx.id[idx])
@@ -652,7 +689,7 @@
 
 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 +719,9 @@
 	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 +839,7 @@
 	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 +848,7 @@
 	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 +858,7 @@
 	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 +869,7 @@
 				    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 +882,7 @@
 	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 +895,7 @@
 	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 +911,47 @@
 				    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 +966,27 @@
 	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)
@@ -953,6 +1010,7 @@
 {
 	unsigned short misc;
 	
+	patch_ad1881(ac97);
 	ac97->build_ops = &patch_ad1985_build_ops;
 	misc = snd_ac97_read(ac97, AC97_AD_MISC);
 	/* switch front/surround line-out/hp-out */
@@ -972,6 +1030,36 @@
 	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 +1082,13 @@
 	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 +1103,6 @@
 
 	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 +1130,27 @@
 		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 */
-	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 default: slot 3,4,7,8,6,9
+	   spdif-in monitor off, analog-spdif off, spdif-in off
+	   center on mic off, surround on line-in off
+	   downmix off, duplicate front off
+	*/
+	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 0);
+
+	/* 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 +1158,37 @@
 	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 +1261,23 @@
 
 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);
+	/* set default: spdif-in enabled,
+	   spdif-in monitor off, spdif-in PCM off
+	   center on mic off, surround on line-in off
+	   duplicate front off
+	*/
+	snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, 1<<15);
 
 	/* full DAC volume */
 	snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808);
@@ -1203,6 +1285,9 @@
 	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 +1397,10 @@
 	/* 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 +1409,9 @@
 	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 -Nru a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
--- a/sound/pci/ac97/ac97_patch.h	Sat Apr  3 19:38:40 2004
+++ b/sound/pci/ac97/ac97_patch.h	Sat Apr  3 19:38:40 2004
@@ -34,6 +34,7 @@
 int patch_sigmatel_stac9721(ac97_t * ac97);
 int patch_sigmatel_stac9744(ac97_t * ac97);
 int patch_sigmatel_stac9756(ac97_t * ac97);
+int patch_sigmatel_stac9758(ac97_t * ac97);
 int patch_cirrus_cs4299(ac97_t * ac97);
 int patch_cirrus_spdif(ac97_t * ac97);
 int patch_conexant(ac97_t * ac97);
@@ -41,6 +42,7 @@
 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 -Nru a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c
--- a/sound/pci/ac97/ac97_pcm.c	Sat Apr  3 19:38:41 2004
+++ b/sound/pci/ac97/ac97_pcm.c	Sat Apr  3 19:38:41 2004
@@ -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"
@@ -88,7 +89,7 @@
 	0xff,				/* slot 6 */
 	AC97_PCM_LFE_DAC_RATE,		/* slot 7 */
 	AC97_PCM_LFE_DAC_RATE,		/* slot 8 */
-	AC97_PCM_FRONT_DAC_RATE,	/* slot 9 */
+	0xff,				/* slot 9 */
 	AC97_PCM_FRONT_DAC_RATE,	/* slot 10 */
 	AC97_PCM_FRONT_DAC_RATE,	/* slot 11 */
   },
@@ -139,7 +140,7 @@
 	0xff,				/* slot 6 */
 	AC97_PCM_LFE_DAC_RATE,		/* slot 7 */
 	AC97_PCM_LFE_DAC_RATE,		/* slot 8 */
-	AC97_PCM_FRONT_DAC_RATE,	/* slot 9 */
+	0xff,				/* slot 9 */
 	AC97_PCM_FRONT_DAC_RATE,	/* slot 10 */
 	AC97_PCM_FRONT_DAC_RATE,	/* slot 11 */
   }
@@ -176,6 +177,7 @@
 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 @@
 	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 -Nru a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c
--- a/sound/pci/ac97/ac97_proc.c	Sat Apr  3 19:38:56 2004
+++ b/sound/pci/ac97/ac97_proc.c	Sat Apr  3 19:38:56 2004
@@ -241,12 +241,13 @@
 		for (idx = 0; idx < 3; idx++)
 			if (ac97->spec.ad18xx.id[idx]) {
 				/* select single codec */
-				snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
+				snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+						     ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
 				snd_ac97_proc_read_main(ac97, buffer, idx);
 				snd_iprintf(buffer, "\n\n");
 			}
 		/* select all codecs */
-		snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+		snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
 		up(&ac97->spec.ad18xx.mutex);
 		
 		snd_iprintf(buffer, "\nAD18XX configuration\n");
@@ -285,11 +286,12 @@
 		for (idx = 0; idx < 3; idx++)
 			if (ac97->spec.ad18xx.id[idx]) {
 				/* select single codec */
-				snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
+				snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000,
+						     ac97->spec.ad18xx.unchained[idx] | ac97->spec.ad18xx.chained[idx]);
 				snd_ac97_proc_regs_read_main(ac97, buffer, idx);
 			}
 		/* select all codecs */
-		snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, 0x7000);
+		snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x7000, 0x7000);
 		up(&ac97->spec.ad18xx.mutex);
 	} else {
 		snd_ac97_proc_regs_read_main(ac97, buffer, 0);
diff -Nru a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c
--- a/sound/pci/ac97/ak4531_codec.c	Sat Apr  3 19:38:41 2004
+++ b/sound/pci/ac97/ak4531_codec.c	Sat Apr  3 19:38:41 2004
@@ -285,7 +285,7 @@
 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 -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
--- a/sound/pci/ali5451/ali5451.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/ali5451/ali5451.c	Sat Apr  3 19:38:55 2004
@@ -1742,7 +1742,8 @@
 	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 -Nru a/sound/pci/als4000.c b/sound/pci/als4000.c
--- a/sound/pci/als4000.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/als4000.c	Sat Apr  3 19:38:55 2004
@@ -99,9 +99,11 @@
 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 @@
 	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 -Nru a/sound/pci/atiixp.c b/sound/pci/atiixp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/atiixp.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/Makefile b/sound/pci/au88x0/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/Makefile	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au8810.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au8810.h b/sound/pci/au88x0/au8810.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au8810.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,211 @@
+/*
+    Aureal Advantage Soundcard driver.
+ */
+
+#define CHIP_AU8810
+
+#define CARD_NAME "Aureal Advantage 3D Sound Processor"
+#define CARD_NAME_SHORT "au8810"
+
+#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 -Nru a/sound/pci/au88x0/au8820.c b/sound/pci/au88x0/au8820.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au8820.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au8820.h b/sound/pci/au88x0/au8820.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au8820.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,209 @@
+/*
+    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"
+
+/* 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 -Nru a/sound/pci/au88x0/au8830.c b/sound/pci/au88x0/au8830.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au8830.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au8830.h b/sound/pci/au88x0/au8830.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au8830.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,256 @@
+/*
+    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"
+
+#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 -Nru a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,425 @@
+/*
+ * 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;
+	int rc;
+
+	/* 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;
+
+	/* 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);
+
+	if ((err = pci_read_config_word(pci, PCI_DEVICE_ID,
+				  &(chip->device))) < 0) {
+		snd_card_free(card);
+		return err;
+	}	
+	if ((err = pci_read_config_word(pci, PCI_VENDOR_ID,
+				  &(chip->vendor))) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	if ((err = pci_read_config_byte(pci, PCI_REVISION_ID,
+				  &(chip->rev))) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+#ifdef CHIP_AU8830
+	if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
+		printk(KERN_ALERT
+		       "vortex: The revision (%x) of your card has not been seen before.\n",
+		       chip->rev);
+		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 -Nru a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,280 @@
+/*
+ *  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 __SOUND_AU88X0_H
+#define __SOUND_AU88X0_H
+
+#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 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))
+/* Check if chip has bug. */
+#define IS_BAD_CHIP(x) (\
+	(x->rev < 3 && x->device == PCI_DEVICE_ID_AUREAL_VORTEX) || \
+	(x->rev < 0xfe && x->device == PCI_DEVICE_ID_AUREAL_VORTEX2) || \
+	(x->rev < 0xfe && x->device == PCI_DEVICE_ID_AUREAL_ADVANTAGE))
+
+
+/* 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 -Nru a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_a3d.c	Sat Apr  3 19:38:57 2004
@@ -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);
+}
+
+static 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 -Nru a/sound/pci/au88x0/au88x0_a3d.h b/sound/pci/au88x0/au88x0_a3d.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_a3d.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_a3ddata.c b/sound/pci/au88x0/au88x0_a3ddata.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_a3ddata.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_core.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,2826 @@
+/*
+ *  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.
+static int mchannels[NR_MIXIN];
+static 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. Revision 0xFE does not seem to need it. */
+ 	printk(KERN_INFO "vortex: revision = 0x%x, device = %d\n", vortex->rev, vortex->device);
+ 	if (IS_BAD_CHIP(vortex)) {
+ 		printk(KERN_INFO "vortex: Erratum workaround enabled.\n");
+ #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: 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: 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 -Nru a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_eq.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_eq.h b/sound/pci/au88x0/au88x0_eq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_eq.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_eqdata.c b/sound/pci/au88x0/au88x0_eqdata.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_eqdata.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_game.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,130 @@
+/*
+ * $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>
+
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+
+#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;
+}
+
+#else
+
+static inline int vortex_gameport_register(vortex_t * vortex) { return 0; }
+static inline int vortex_gameport_unregister(vortex_t * vortex) { return 0; }
+
+#endif
diff -Nru a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_mixer.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_mpu401.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_pcm.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,527 @@
+/*
+ *  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 PCM ALSA driver.
+ *
+ * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet.
+ * It remains stuck,and DMA transfers do not happen.
+ *
+ */
+
+#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 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);
+	
+	// The above should be used, as soon as ALSA gets updated.
+	/*
+	snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci_dev, pcm,
+						 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 -Nru a/sound/pci/au88x0/au88x0_sb.h b/sound/pci/au88x0/au88x0_sb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_sb.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_synth.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_wt.h b/sound/pci/au88x0/au88x0_wt.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_wt.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_xtalk.c b/sound/pci/au88x0/au88x0_xtalk.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_xtalk.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/au88x0/au88x0_xtalk.h b/sound/pci/au88x0/au88x0_xtalk.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/au88x0/au88x0_xtalk.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/azt3328.c b/sound/pci/azt3328.c
--- a/sound/pci/azt3328.c	Sat Apr  3 19:38:44 2004
+++ b/sound/pci/azt3328.c	Sat Apr  3 19:38:44 2004
@@ -1253,7 +1253,8 @@
 	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 -Nru a/sound/pci/bt87x.c b/sound/pci/bt87x.c
--- a/sound/pci/bt87x.c	Sat Apr  3 19:38:44 2004
+++ b/sound/pci/bt87x.c	Sat Apr  3 19:38:44 2004
@@ -167,8 +167,8 @@
 	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 @@
 	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 @@
 	*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 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 @@
 	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 @@
 	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 -Nru a/sound/pci/cmipci.c b/sound/pci/cmipci.c
--- a/sound/pci/cmipci.c	Sat Apr  3 19:38:45 2004
+++ b/sound/pci/cmipci.c	Sat Apr  3 19:38:45 2004
@@ -2087,7 +2087,8 @@
 	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 @@
 	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 @@
 	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 @@
 #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 -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c
--- a/sound/pci/cs4281.c	Sat Apr  3 19:38:56 2004
+++ b/sound/pci/cs4281.c	Sat Apr  3 19:38:56 2004
@@ -1039,7 +1039,8 @@
 	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 -Nru a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
--- a/sound/pci/cs46xx/cs46xx.c	Sat Apr  3 19:38:56 2004
+++ b/sound/pci/cs46xx/cs46xx.c	Sat Apr  3 19:38:56 2004
@@ -51,7 +51,7 @@
 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
 static int external_amp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
 static int thinkpad[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
-static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
+static int mmap_valid[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
 
 MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(index, "Index value for the CS46xx soundcard.");
@@ -70,7 +70,7 @@
 MODULE_PARM_SYNTAX(thinkpad, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
 MODULE_PARM(mmap_valid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(mmap_valid, "Support OSS mmap.");
-MODULE_PARM_SYNTAX(mmap_valid, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC);
+MODULE_PARM_SYNTAX(mmap_valid, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
 
 static struct pci_device_id snd_cs46xx_ids[] = {
         { 0x1013, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },   /* CS4280 */
@@ -219,7 +219,7 @@
 
 #ifndef MODULE
 
-/* format is: snd-cs46xx=enable,index,id */
+/* format is: snd-cs46xx=enable,index,id,mmap_valid,external_amp,thinkpad */
 
 static int __init alsa_card_cs46xx_setup(char *str)
 {
@@ -229,7 +229,10 @@
 		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_id(&str,&id[nr_dev]) == 2 &&
+	       get_option(&str,&mmap_valid[nr_dev]) == 2 &&
+	       get_option(&str,&external_amp[nr_dev]) == 2 &&
+	       get_option(&str,&thinkpad[nr_dev]) == 2);
 	nr_dev++;
 	return 1;
 }
diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
--- a/sound/pci/cs46xx/cs46xx_lib.c	Sat Apr  3 19:38:41 2004
+++ b/sound/pci/cs46xx/cs46xx_lib.c	Sat Apr  3 19:38:41 2004
@@ -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 @@
 	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 @@
 	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 @@
 			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 @@
 		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 @@
 #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 @@
 #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_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 @@
 	/* 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 @@
 		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 @@
 #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 @@
 #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 @@
 	   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 @@
 	/* 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 {
 	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 @@
 #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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	/* 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 @@
 #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);
@@ -3912,6 +3929,10 @@
 	strcpy(region->name, "CS46xx_BA1_reg");
 	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);
diff -Nru a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
--- a/sound/pci/cs46xx/dsp_spos.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/cs46xx/dsp_spos.c	Sat Apr  3 19:38:55 2004
@@ -823,7 +823,7 @@
 		entry->private_data = chip;
 		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
 		entry->c.text.read_size = 512;
-		entry->c.text.read = cs46xx_dsp_proc_task_tree_read;;
+		entry->c.text.read = cs46xx_dsp_proc_task_tree_read;
 		if (snd_info_register(entry) < 0) {
 			snd_info_free_entry(entry);
 			entry = NULL;
@@ -836,7 +836,7 @@
 		entry->private_data = chip;
 		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
 		entry->c.text.read_size = 1024;
-		entry->c.text.read = cs46xx_dsp_proc_scb_read;;
+		entry->c.text.read = cs46xx_dsp_proc_scb_read;
 		if (snd_info_register(entry) < 0) {
 			snd_info_free_entry(entry);
 			entry = NULL;
diff -Nru a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
--- a/sound/pci/emu10k1/emu10k1.c	Sat Apr  3 19:38:40 2004
+++ b/sound/pci/emu10k1/emu10k1.c	Sat Apr  3 19:38:40 2004
@@ -80,7 +80,9 @@
 
 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 -Nru a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
--- a/sound/pci/emu10k1/emu10k1_callback.c	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/emu10k1/emu10k1_callback.c	Sat Apr  3 19:38:42 2004
@@ -405,7 +405,7 @@
 	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
@@ -426,7 +426,7 @@
 		snd_emu10k1_ptr_write(hw, CDF, ch, sample);
 
 		/* invalidate maps */
-		temp = ((unsigned int)hw->silent_page_dmaaddr << 1) | MAP_PTI_MASK;
+		temp = ((unsigned int)hw->silent_page.addr << 1) | MAP_PTI_MASK;
 		snd_emu10k1_ptr_write(hw, MAPA, ch, temp);
 		snd_emu10k1_ptr_write(hw, MAPB, ch, temp);
 		
diff -Nru a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
--- a/sound/pci/emu10k1/emu10k1_main.c	Sat Apr  3 19:38:56 2004
+++ b/sound/pci/emu10k1/emu10k1_main.c	Sat Apr  3 19:38:56 2004
@@ -97,7 +97,8 @@
 	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 @@
 	/*
 	 *  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 @@
        	}
 	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 @@
 	}
 	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 @@
 		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 -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
--- a/sound/pci/emu10k1/emufx.c	Sat Apr  3 19:38:43 2004
+++ b/sound/pci/emu10k1/emufx.c	Sat Apr  3 19:38:43 2004
@@ -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 @@
 
 	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 @@
 	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 @@
 		}
 		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 @@
 	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 -Nru a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
--- a/sound/pci/emu10k1/emupcm.c	Sat Apr  3 19:38:40 2004
+++ b/sound/pci/emu10k1/emupcm.c	Sat Apr  3 19:38:40 2004
@@ -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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 -Nru a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c
--- a/sound/pci/emu10k1/emuproc.c	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/emu10k1/emuproc.c	Sat Apr  3 19:38:42 2004
@@ -117,7 +117,7 @@
 	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 -Nru a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
--- a/sound/pci/emu10k1/memory.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/emu10k1/memory.c	Sat Apr  3 19:38:55 2004
@@ -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)
@@ -62,7 +62,7 @@
 	page *= UNIT_PAGES;
 	for (i = 0; i < UNIT_PAGES; i++, page++)
 		/* do not increment ptr */
-		__set_ptb_entry(emu, page, emu->silent_page_dmaaddr);
+		__set_ptb_entry(emu, page, emu->silent_page.addr);
 }
 #endif /* PAGE_SIZE */
 
@@ -297,7 +297,6 @@
 	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 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 @@
 	/* 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 @@
 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 -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c
--- a/sound/pci/ens1370.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/ens1370.c	Sat Apr  3 19:38:55 2004
@@ -434,8 +434,8 @@
 	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 @@
 #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 @@
 #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 @@
 	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 @@
 	}
 	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 @@
 	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 -Nru a/sound/pci/es1938.c b/sound/pci/es1938.c
--- a/sound/pci/es1938.c	Sat Apr  3 19:38:45 2004
+++ b/sound/pci/es1938.c	Sat Apr  3 19:38:45 2004
@@ -946,17 +946,14 @@
 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 @@
 		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 @@
 	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 -Nru a/sound/pci/es1968.c b/sound/pci/es1968.c
--- a/sound/pci/es1968.c	Sat Apr  3 19:38:54 2004
+++ b/sound/pci/es1968.c	Sat Apr  3 19:38:54 2004
@@ -1495,13 +1495,15 @@
 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 -Nru a/sound/pci/fm801.c b/sound/pci/fm801.c
--- a/sound/pci/fm801.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/fm801.c	Sat Apr  3 19:38:55 2004
@@ -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 @@
 	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 -Nru a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c
--- a/sound/pci/ice1712/amp.c	Sat Apr  3 19:38:43 2004
+++ b/sound/pci/ice1712/amp.c	Sat Apr  3 19:38:43 2004
@@ -38,6 +38,7 @@
 	/* only use basic functionality for now */
 
 	ice->num_total_dacs = 2;	/* only PSDOUT0 is connected */
+	ice->num_total_adcs = 2;
 
 	return 0;
 }
diff -Nru a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
--- a/sound/pci/ice1712/aureon.c	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/ice1712/aureon.c	Sat Apr  3 19:38:42 2004
@@ -409,10 +409,13 @@
 	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 -Nru a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
--- a/sound/pci/ice1712/delta.c	Sat Apr  3 19:38:41 2004
+++ b/sound/pci/ice1712/delta.c	Sat Apr  3 19:38:41 2004
@@ -90,6 +90,7 @@
 		tmp |= ICE1712_DELTA_1010LT_CCLK | ICE1712_DELTA_1010LT_CS_CS8427;
 		break;
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
+	case ICE1712_SUBDEVICE_DELTA410:
 		tmp |= ICE1712_DELTA_AP_CCLK | ICE1712_DELTA_AP_CS_CODEC;
 		tmp &= ~ICE1712_DELTA_AP_CS_DIGITAL;
 		break;
@@ -112,6 +113,7 @@
 		tmp |= ICE1712_DELTA_1010LT_CS_NONE;
 		break;
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
+	case ICE1712_SUBDEVICE_DELTA410:
 		tmp |= ICE1712_DELTA_AP_CS_DIGITAL;
 		break;
 	case ICE1712_SUBDEVICE_VX442:
@@ -511,20 +513,25 @@
 	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 -Nru a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
--- a/sound/pci/ice1712/ews.c	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/ice1712/ews.c	Sat Apr  3 19:38:42 2004
@@ -406,15 +406,18 @@
 	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 -Nru a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
--- a/sound/pci/ice1712/hoontech.c	Sat Apr  3 19:38:44 2004
+++ b/sound/pci/ice1712/hoontech.c	Sat Apr  3 19:38:44 2004
@@ -153,6 +153,7 @@
 	int box, chn;
 
 	ice->num_total_dacs = 8;
+	ice->num_total_adcs = 8;
 
 	ice->hoontech_boxbits[0] = 
 	ice->hoontech_boxbits[1] = 
diff -Nru a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
--- a/sound/pci/ice1712/ice1712.c	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/ice1712/ice1712.c	Sat Apr  3 19:38:42 2004
@@ -82,6 +82,7 @@
 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 omni[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};	/* Delta44 & 66 Omni I/O support */
+static int cs8427_timeout[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 500}; /* CS8427 S/PDIF transciever reset timeout value in msec */
 
 MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(index, "Index value for ICE1712 soundcard.");
@@ -95,6 +96,9 @@
 MODULE_PARM(omni, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(omni, "Enable Midiman M-Audio Delta Omni I/O support.");
 MODULE_PARM_SYNTAX(omni, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
+MODULE_PARM(cs8427_timeout, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+MODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec resolution.");
+MODULE_PARM_SYNTAX(cs8427_timeout, SNDRV_ENABLED ", allows:{{1,1000}},default=500,skill:advanced");
 
 #ifndef PCI_VENDOR_ID_ICE
 #define PCI_VENDOR_ID_ICE		0x1412
@@ -386,7 +390,9 @@
 {
 	int err;
 
-	if ((err = snd_cs8427_create(ice->i2c, addr, &ice->cs8427)) < 0) {
+	if ((err = snd_cs8427_create(ice->i2c, addr,
+				     (ice->cs8427_timeout * HZ) / 1000,
+				     &ice->cs8427)) < 0) {
 		snd_printk("CS8427 initialization failed\n");
 		return err;
 	}
@@ -886,7 +892,8 @@
 	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 +929,8 @@
 	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 +1277,8 @@
 	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 +1390,7 @@
 }
 
 
-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 +1409,44 @@
 		.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 +1456,46 @@
 	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);
 	}
@@ -1450,10 +1511,10 @@
 static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
 {
 	int err;
+	ac97_t ac97;
+	ac97_bus_t bus, *pbus;
 
 	if (ice_has_con_ac97(ice)) {
-		ac97_bus_t bus, *pbus;
-		ac97_t ac97;
 		memset(&bus, 0, sizeof(bus));
 		bus.write = snd_ice1712_ac97_write;
 		bus.read = snd_ice1712_ac97_read;
@@ -1472,8 +1533,6 @@
 	}
 
 	if (! (ice->eeprom.data[ICE_EEP1_ACLINK] & ICE1712_CFG_PRO_I2S)) {
-		ac97_bus_t bus, *pbus;
-		ac97_t ac97;
 		memset(&bus, 0, sizeof(bus));
 		bus.write = snd_ice1712_pro_ac97_write;
 		bus.read = snd_ice1712_pro_ac97_read;
@@ -2349,6 +2408,7 @@
 static int __devinit snd_ice1712_create(snd_card_t * card,
 					struct pci_dev *pci,
 					int omni,
+					int cs8427_timeout,
 					ice1712_t ** r_ice1712)
 {
 	ice1712_t *ice;
@@ -2373,8 +2433,14 @@
 	if (ice == NULL)
 		return -ENOMEM;
 	ice->omni = omni ? 1 : 0;
+	if (cs8427_timeout < 1)
+		cs8427_timeout = 1;
+	else if (cs8427_timeout > 1000)
+		cs8427_timeout = 1000;
+	ice->cs8427_timeout = cs8427_timeout;
 	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;
@@ -2491,7 +2557,7 @@
 	strcpy(card->driver, "ICE1712");
 	strcpy(card->shortname, "ICEnsemble ICE1712");
 	
-	if ((err = snd_ice1712_create(card, pci, omni[dev], &ice)) < 0) {
+	if ((err = snd_ice1712_create(card, pci, omni[dev], cs8427_timeout[dev], &ice)) < 0) {
 		snd_card_free(card);
 		return err;
 	}
diff -Nru a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
--- a/sound/pci/ice1712/ice1712.h	Sat Apr  3 19:38:41 2004
+++ b/sound/pci/ice1712/ice1712.h	Sat Apr  3 19:38:41 2004
@@ -330,11 +330,15 @@
 	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;
@@ -342,6 +346,7 @@
 	snd_i2c_bus_t *i2c;		/* I2C bus */
 	snd_i2c_device_t *cs8404;	/* CS8404A I2C device */
 	snd_i2c_device_t *cs8427;	/* CS8427 I2C device */
+	unsigned int cs8427_timeout;	/* CS8427 reset timeout in HZ/100 */
 	snd_i2c_device_t *i2cdevs[2];	/* additional i2c devices */
 	
 	struct ice1712_gpio {
diff -Nru a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
--- a/sound/pci/ice1712/ice1724.c	Sat Apr  3 19:38:43 2004
+++ b/sound/pci/ice1712/ice1724.c	Sat Apr  3 19:38:43 2004
@@ -237,6 +237,18 @@
 				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 @@
 	.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 @@
 	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 @@
 
 	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 @@
 /*
  */
 
-#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 @@
 				    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 @@
 	.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 @@
 	.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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 	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 @@
  * 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 @@
 	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 @@
 	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 @@
 	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 @@
 
 
 /*
+ * 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 @@
 	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 @@
 		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 -Nru a/sound/pci/ice1712/prodigy.c b/sound/pci/ice1712/prodigy.c
--- a/sound/pci/ice1712/prodigy.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/ice1712/prodigy.c	Sat Apr  3 19:38:55 2004
@@ -585,6 +585,7 @@
 	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 -Nru a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
--- a/sound/pci/ice1712/revo.c	Sat Apr  3 19:38:44 2004
+++ b/sound/pci/ice1712/revo.c	Sat Apr  3 19:38:44 2004
@@ -128,6 +128,7 @@
 	switch (ice->eeprom.subvendor) {
 	case VT1724_SUBDEVICE_REVOLUTION71:
 		ice->num_total_dacs = 8;
+		ice->num_total_adcs = 4;
 		break;
 	default:
 		snd_BUG();
diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
--- a/sound/pci/intel8x0.c	Sat Apr  3 19:38:44 2004
+++ b/sound/pci/intel8x0.c	Sat Apr  3 19:38:44 2004
@@ -55,6 +55,8 @@
 		"{Intel,82801CA-ICH3},"
 		"{Intel,82801DB-ICH4},"
 		"{Intel,ICH5},"
+		"{Intel,ICH6},"
+		"{Intel,6300ESB},"
 		"{Intel,MX440},"
 		"{SiS,SI7012},"
 		"{NVidia,nForce Audio},"
@@ -94,7 +96,7 @@
 MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0");
 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");
 #ifdef SUPPORT_JOYSTICK
 MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
 MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard.");
@@ -131,6 +133,12 @@
 #ifndef PCI_DEVICE_ID_INTEL_ICH5
 #define PCI_DEVICE_ID_INTEL_ICH5	0x24d5
 #endif
+#ifndef PCI_DEVICE_ID_INTEL_ESB_5
+#define PCI_DEVICE_ID_INTEL_ESB_5	0x25a6
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_ICH6_3
+#define PCI_DEVICE_ID_INTEL_ICH6_3	0x266e
+#endif
 #ifndef PCI_DEVICE_ID_SI_7012
 #define PCI_DEVICE_ID_SI_7012		0x7012
 #endif
@@ -143,6 +151,9 @@
 #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 };
 
@@ -195,6 +206,11 @@
 
 /* global block */
 #define ICH_REG_GLOB_CNT		0x2c	/* dword - global control */
+#define   ICH_PCM_SPDIF_MASK	0xc0000000	/* s/pdif pcm slot mask (ICH4) */
+#define   ICH_PCM_SPDIF_NONE	0x00000000	/* reserved - undefined */
+#define   ICH_PCM_SPDIF_78	0x40000000	/* s/pdif pcm on slots 7&8 */
+#define   ICH_PCM_SPDIF_69	0x80000000	/* s/pdif pcm on slots 6&9 */
+#define   ICH_PCM_SPDIF_1011	0xc0000000	/* s/pdif pcm on slots 10&11 */
 #define   ICH_PCM_20BIT		0x00400000	/* 20-bit samples (ICH4) */
 #define   ICH_PCM_246_MASK	0x00300000	/* 6 channels (not all chips) */
 #define   ICH_PCM_6		0x00200000	/* 6 channels (not all chips) */
@@ -396,6 +412,8 @@
 	unsigned long remap_bmaddr;
 	struct resource *res_bm;
 
+	struct snd_dma_device dma_dev;
+
 	struct pci_dev *pci;
 	snd_card_t *card;
 
@@ -420,8 +438,7 @@
 	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;
@@ -438,11 +455,14 @@
 	{ 0x8086, 0x2485, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* ICH3 */
 	{ 0x8086, 0x24c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH4 */
 	{ 0x8086, 0x24d5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH5 */
+	{ 0x8086, 0x25a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB */
+	{ 0x8086, 0x266e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH6 */
 	{ 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL },	/* 440MX */
 	{ 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },	/* SI7012 */
 	{ 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 +824,17 @@
 	spin_lock(&chip->reg_lock);
 	status = igetdword(chip, chip->int_sta_reg);
 	if ((status & chip->int_sta_mask) == 0) {
-		if (status)
+		if (status) {
+			/* ack */
 			iputdword(chip, chip->int_sta_reg, status);
+			/* some Nforce[2] boards have problems when
+			   IRQ_NONE is returned here.
+			*/
+			if (chip->device_type != DEVICE_NFORCE)
+				status = 0;
+		}
 		spin_unlock(&chip->reg_lock);
-		return IRQ_NONE;
+		return IRQ_RETVAL(status);
 	}
 
 	for (i = 0; i < chip->bdbars_count; i++) {
@@ -1017,6 +1044,7 @@
 {
 	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 +1052,9 @@
 		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 +1109,12 @@
 {
 	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 +1464,8 @@
 		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 +1687,18 @@
 
 static struct ac97_quirk ac97_quirks[] __devinitdata = {
 	{
+		.vendor = 0x0e11,
+		.device = 0x00b8,
+		.name = "Compaq Evo D510C",
+		.type = AC97_TUNE_HP_ONLY
+	},
+	{
+		.vendor = 0x1014,
+		.device = 0x1f00,
+		.name = "MS-9128",
+		.type = AC97_TUNE_ALC_JACK
+	},
+	{
 		.vendor = 0x1028,
 		.device = 0x00d8,
 		.name = "Dell Precision 530",	/* AD1885 */
@@ -1741,6 +1774,12 @@
 	},
 	{
 		.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 +1798,7 @@
 		.name = "Intel ICH5/AD1985",
 		.type = AC97_TUNE_AD_SHARING
 	},
+#if 0 /* FIXME: this seems wrong on most boards */
 	{
 		.vendor = 0x8086,
 		.device = 0xa000,
@@ -1766,6 +1806,7 @@
 		.name = "Intel ICH5/AD1985",
 		.type = AC97_TUNE_HP_ONLY
 	},
+#endif
 	{ } /* terminator */
 };
 
@@ -2116,10 +2157,10 @@
 	/* --- */
 	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 +2550,27 @@
 	/* 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;
@@ -2563,10 +2608,13 @@
 	{ PCI_DEVICE_ID_INTEL_ICH3, "Intel 82801CA-ICH3" },
 	{ PCI_DEVICE_ID_INTEL_ICH4, "Intel 82801DB-ICH4" },
 	{ PCI_DEVICE_ID_INTEL_ICH5, "Intel ICH5" },
+	{ PCI_DEVICE_ID_INTEL_ESB_5, "Intel 6300ESB" },
+	{ PCI_DEVICE_ID_INTEL_ICH6_3, "Intel ICH6" },
 	{ PCI_DEVICE_ID_SI_7012, "SiS SI7012" },
 	{ 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" },
@@ -2694,6 +2742,7 @@
 
 	pci_read_config_word(pci, 0xe6, &val);
 #ifdef SUPPORT_JOYSTICK
+	val &= ~0x100;
 	if (joystick[dev]) {
 		if (! request_region(ich_gameport.io, 8, "ICH gameport")) {
 			printk(KERN_WARNING "intel8x0: cannot grab gameport 0x%x\n",  ich_gameport.io);
@@ -2706,6 +2755,7 @@
 	}
 #endif
 #ifdef SUPPORT_MIDI
+	val &= ~0x20;
 	if (mpu_port[dev] > 0) {
 		if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) {
 			u8 b;
diff -Nru a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/intel8x0m.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
--- a/sound/pci/korg1212/korg1212.c	Sat Apr  3 19:38:40 2004
+++ b/sound/pci/korg1212/korg1212.c	Sat Apr  3 19:38:40 2004
@@ -347,9 +347,14 @@
 	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 @@
         KorgAudioBuffer  * recordDataBufsPtr;
 
 	KorgSharedBuffer * sharedBufferPtr;
+
 	u32 RecDataPhy;
 	u32 PlayDataPhy;
 	unsigned long sharedBufferPhy;
@@ -1238,10 +1244,10 @@
 
         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 @@
         // ----------------------------------------------------
         // 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 @@
         // ------------------------------------------------------
         // 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 @@
         // ----------------------------------------------------
         // 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 @@
         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 @@
 		   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 @@
 
         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 @@
         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 @@
                "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 -Nru a/sound/pci/maestro3.c b/sound/pci/maestro3.c
--- a/sound/pci/maestro3.c	Sat Apr  3 19:38:44 2004
+++ b/sound/pci/maestro3.c	Sat Apr  3 19:38:44 2004
@@ -1816,7 +1816,8 @@
 	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 -Nru a/sound/pci/mixart/Makefile b/sound/pci/mixart/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/Makefile	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart.h	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,242 @@
+/*
+ * 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 <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 -Nru a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_core.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_core.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_hwdep.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/mixart/mixart_hwdep.h b/sound/pci/mixart/mixart_hwdep.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_hwdep.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_mixer.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/mixart/mixart_mixer.h b/sound/pci/mixart/mixart_mixer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pci/mixart/mixart_mixer.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pci/rme32.c b/sound/pci/rme32.c
--- a/sound/pci/rme32.c	Sat Apr  3 19:38:56 2004
+++ b/sound/pci/rme32.c	Sat Apr  3 19:38:56 2004
@@ -1378,9 +1378,10 @@
 	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 @@
 		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 -Nru a/sound/pci/rme96.c b/sound/pci/rme96.c
--- a/sound/pci/rme96.c	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/rme96.c	Sat Apr  3 19:38:42 2004
@@ -1718,7 +1718,11 @@
 
 	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 @@
 		
 		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 -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
--- a/sound/pci/rme9652/hdsp.c	Sat Apr  3 19:38:42 2004
+++ b/sound/pci/rme9652/hdsp.c	Sat Apr  3 19:38:42 2004
@@ -568,7 +568,10 @@
 	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_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 @@
 {
 	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 @@
 
 	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 @@
 
 	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 -Nru a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
--- a/sound/pci/rme9652/rme9652.c	Sat Apr  3 19:38:43 2004
+++ b/sound/pci/rme9652/rme9652.c	Sat Apr  3 19:38:43 2004
@@ -314,7 +314,10 @@
 	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_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 -Nru a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
--- a/sound/pci/sonicvibes.c	Sat Apr  3 19:38:54 2004
+++ b/sound/pci/sonicvibes.c	Sat Apr  3 19:38:54 2004
@@ -886,7 +886,8 @@
 	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 -Nru a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
--- a/sound/pci/trident/trident_main.c	Sat Apr  3 19:38:45 2004
+++ b/sound/pci/trident/trident_main.c	Sat Apr  3 19:38:45 2004
@@ -1009,8 +1009,6 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	}
 	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 @@
 	/* 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 @@
 		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 @@
 	}
 	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 @@
 	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 -Nru a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c
--- a/sound/pci/trident/trident_memory.c	Sat Apr  3 19:38:45 2004
+++ b/sound/pci/trident/trident_memory.c	Sat Apr  3 19:38:45 2004
@@ -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 */
@@ -76,8 +76,8 @@
 static inline void set_silent_tlb(trident_t *trident, int page)
 {
 	page <<= 1;
-	__set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page, trident->tlb.silent_page_dmaaddr);
-	__set_tlb_bus(trident, page+1, (unsigned long)trident->tlb.silent_page, trident->tlb.silent_page_dmaaddr);
+	__set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr);
+	__set_tlb_bus(trident, page+1, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr);
 }
 
 #else
@@ -111,7 +111,7 @@
 	int i;
 	page *= UNIT_PAGES;
 	for (i = 0; i < UNIT_PAGES; i++, page++)
-		__set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page, trident->tlb.silent_page_dmaaddr);
+		__set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr);
 }
 
 #endif /* PAGE_SIZE */
@@ -191,7 +191,6 @@
 	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 @@
 	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_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 @@
 	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 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 @@
 	 * 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 -Nru a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c
--- a/sound/pci/trident/trident_synth.c	Sat Apr  3 19:38:43 2004
+++ b/sound/pci/trident/trident_synth.c	Sat Apr  3 19:38:43 2004
@@ -507,7 +507,6 @@
 					 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 @@
 
 	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 @@
 		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 -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c
--- a/sound/pci/via82xx.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/via82xx.c	Sat Apr  3 19:38:55 2004
@@ -107,7 +107,7 @@
 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 @@
         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 @@
 };
 
 
+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 @@
 			   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 @@
 				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 @@
 			} 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 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 @@
 	 * 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 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 @@
 				  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 @@
 	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 @@
 	/* 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 @@
 	/* 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 @@
 	/* 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 @@
 	/* 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 @@
 	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 @@
 	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 @@
 		.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 @@
 	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 @@
 		{ .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 -Nru a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
--- a/sound/pci/ymfpci/ymfpci_main.c	Sat Apr  3 19:38:55 2004
+++ b/sound/pci/ymfpci/ymfpci_main.c	Sat Apr  3 19:38:55 2004
@@ -541,20 +541,15 @@
 
 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 @@
 			  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 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 	       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 @@
 	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 @@
 #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);
@@ -2275,6 +2273,10 @@
 		return -EBUSY;
 	}
 	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) {
diff -Nru a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig
--- a/sound/pcmcia/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/sound/pcmcia/Kconfig	Sat Apr  3 19:38:43 2004
@@ -6,13 +6,21 @@
 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 -Nru a/sound/pcmcia/Makefile b/sound/pcmcia/Makefile
--- a/sound/pcmcia/Makefile	Sat Apr  3 19:38:40 2004
+++ b/sound/pcmcia/Makefile	Sat Apr  3 19:38:40 2004
@@ -3,6 +3,4 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-obj-$(CONFIG_SND) += vx/
-
-
+obj-$(CONFIG_SND) += vx/ pdaudiocf/
diff -Nru a/sound/pcmcia/pdaudiocf/Makefile b/sound/pcmcia/pdaudiocf/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pcmcia/pdaudiocf/Makefile	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,425 @@
+/*
+ * 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"
+#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 -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,316 @@
+/*
+ * 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"
+#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 -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c	Sat Apr  3 19:38:57 2004
@@ -0,0 +1,324 @@
+/*
+ * 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"
+#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 -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c	Sat Apr  3 19:38:57 2004
@@ -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 -Nru a/sound/ppc/Kconfig b/sound/ppc/Kconfig
--- a/sound/ppc/Kconfig	Sat Apr  3 19:38:43 2004
+++ b/sound/ppc/Kconfig	Sat Apr  3 19:38:43 2004
@@ -6,6 +6,7 @@
 config SND_POWERMAC
 	tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
 	depends on SND
+	select SND_PCM
 
 endmenu
 
diff -Nru a/sound/ppc/pmac.c b/sound/ppc/pmac.c
--- a/sound/ppc/pmac.c	Sat Apr  3 19:38:57 2004
+++ b/sound/ppc/pmac.c	Sat Apr  3 19:38:57 2004
@@ -664,7 +664,9 @@
 	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_dma_continuous_data(GFP_KERNEL),
+					      64 * 1024, 64 * 1024);
 
 	return 0;
 }
diff -Nru a/sound/ppc/powermac.c b/sound/ppc/powermac.c
--- a/sound/ppc/powermac.c	Sat Apr  3 19:38:56 2004
+++ b/sound/ppc/powermac.c	Sat Apr  3 19:38:56 2004
@@ -36,7 +36,7 @@
 
 static int index = SNDRV_DEFAULT_IDX1;		/* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;		/* ID for this card */
-static int enable = 1;
+/* static int enable = 1; */
 #ifdef PMAC_SUPPORT_PCM_BEEP
 static int enable_beep = 1;
 #endif
@@ -47,9 +47,9 @@
 MODULE_PARM(id, "s");
 MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip.");
 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-MODULE_PARM(enable, "i");
-MODULE_PARM_DESC(enable, "Enable this soundchip.");
-MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
+/* MODULE_PARM(enable, "i");
+   MODULE_PARM_DESC(enable, "Enable this soundchip.");
+   MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); */
 #ifdef PMAC_SUPPORT_PCM_BEEP
 MODULE_PARM(enable_beep, "i");
 MODULE_PARM_DESC(enable_beep, "Enable beep using PCM.");
@@ -183,6 +183,8 @@
 
 static int __init alsa_card_pmac_setup(char *str)
 {
+	int __attribute__ ((__unused__)) enable = 1;
+
 	(void)(get_option(&str,&enable) == 2 &&
 	       get_option(&str,&index) == 2 &&
 	       get_id(&str,&id) == 2
diff -Nru a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
--- a/sound/ppc/tumbler.c	Sat Apr  3 19:38:40 2004
+++ b/sound/ppc/tumbler.c	Sat Apr  3 19:38:40 2004
@@ -94,6 +94,7 @@
 	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 @@
 		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 @@
 	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 @@
 	  .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 @@
 		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 -Nru a/sound/sparc/Kconfig b/sound/sparc/Kconfig
--- a/sound/sparc/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/sound/sparc/Kconfig	Sat Apr  3 19:38:54 2004
@@ -6,11 +6,13 @@
 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 -Nru a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
--- a/sound/sparc/amd7930.c	Sat Apr  3 19:38:41 2004
+++ b/sound/sparc/amd7930.c	Sat Apr  3 19:38:41 2004
@@ -791,7 +791,9 @@
 	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 -Nru a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
--- a/sound/sparc/cs4231.c	Sat Apr  3 19:38:41 2004
+++ b/sound/sparc/cs4231.c	Sat Apr  3 19:38:41 2004
@@ -1570,13 +1570,15 @@
 
 #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_DEV,
+						      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 -Nru a/sound/synth/Makefile b/sound/synth/Makefile
--- a/sound/synth/Makefile	Sat Apr  3 19:38:40 2004
+++ b/sound/synth/Makefile	Sat Apr  3 19:38:40 2004
@@ -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 -Nru a/sound/usb/Kconfig b/sound/usb/Kconfig
--- a/sound/usb/Kconfig	Sat Apr  3 19:38:54 2004
+++ b/sound/usb/Kconfig	Sat Apr  3 19:38:54 2004
@@ -6,6 +6,8 @@
 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 -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- a/sound/usb/usbaudio.c	Sat Apr  3 19:38:54 2004
+++ b/sound/usb/usbaudio.c	Sat Apr  3 19:38:54 2004
@@ -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_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);
@@ -105,6 +104,7 @@
  */
 
 #define MAX_PACKS	10	
+#define MAX_PACKS_HS	(MAX_PACKS * 8)	/* in high speed mode */
 #define MAX_URBS	5	/* max. 20ms long packets */
 #define SYNC_URBS	2	/* always two urbs for sync */
 #define MIN_PACKS_URB	1	/* minimum 1 packet per urb */
@@ -117,7 +117,7 @@
 	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 */
@@ -162,8 +162,8 @@
 	unsigned int datapipe;   /* the data i/o pipe */
 	unsigned int syncpipe;   /* 1 - async out or adaptive in */
 	unsigned int syncinterval;  /* P for adaptive mode, 0 otherwise */
-	unsigned int freqn;      /* nominal sampling rate in USB format, i.e. fs/1000 in Q10.14 */
-	unsigned int freqm;      /* momentary sampling rate in USB format, i.e. fs/1000 in Q10.14 */
+	unsigned int freqn;      /* nominal sampling rate in fs/fps in Q16.16 format */
+	unsigned int freqm;      /* momentary sampling rate in fs/fps in Q16.16 format */
 	unsigned int freqmax;    /* maximum sampling rate, used for buffer management */
 	unsigned int phase;      /* phase accumulator */
 	unsigned int maxpacksize;	/* max packet size in bytes */
@@ -171,7 +171,7 @@
 	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 */
 
@@ -185,7 +185,7 @@
 	unsigned int nurbs;			/* # urbs */
 	snd_urb_ctx_t dataurb[MAX_URBS];	/* data urb table */
 	snd_urb_ctx_t syncurb[SYNC_URBS];	/* sync urb table */
-	char syncbuf[SYNC_URBS * MAX_PACKS * 3]; /* sync buffer; it's so small - let's get static */
+	char syncbuf[SYNC_URBS * MAX_PACKS * 4]; /* sync buffer; it's so small - let's get static */
 	char *tmpbuf;			/* temporary buffer for playback */
 
 	u64 formats;			/* format bitmasks (all or'ed) */
@@ -201,6 +201,7 @@
 	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;
 };
@@ -218,17 +219,38 @@
 
 
 /*
- * convert a sampling rate into USB format (fs/1000 in Q10.14)
- * this will overflow at approx 2MSPS
+ * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
+ * this will overflow at approx 524 kHz
  */
-inline static unsigned get_usb_rate(unsigned int rate)
+inline static unsigned get_usb_full_speed_rate(unsigned int rate)
 {
-	return ((rate << 11) + 62) / 125;
+	return ((rate << 13) + 62) / 125;
+}
+
+/*
+ * convert a sampling rate into USB high speed format (fs/8000 in Q16.16)
+ * this will overflow at approx 4 MHz
+ */
+inline static unsigned get_usb_high_speed_rate(unsigned int rate)
+{
+	return ((rate << 10) + 62) / 125;
+}
+
+/* convert our full speed USB rate into sampling rate in Hz */
+inline static unsigned get_full_speed_hz(unsigned int usb_rate)
+{
+	return (usb_rate * 125 + (1 << 12)) >> 13;
+}
+
+/* convert our high speed USB rate into sampling rate in Hz */
+inline static unsigned get_high_speed_hz(unsigned int usb_rate)
+{
+	return (usb_rate * 125 + (1 << 9)) >> 10;
 }
 
 
 /*
- * prepare urb for capture sync pipe
+ * prepare urb for full speed capture sync pipe
  *
  * fill the length and offset of each urb descriptor.
  * the fixed 10.14 frequency is passed through the pipe.
@@ -243,14 +265,40 @@
 
 	urb->number_of_packets = ctx->packets;
 	urb->dev = ctx->subs->dev; /* we need to set this at each time */
-	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 3, cp += 3) {
+	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {
 		urb->iso_frame_desc[i].length = 3;
 		urb->iso_frame_desc[i].offset = offs;
+		cp[0] = subs->freqn >> 2;
+		cp[1] = subs->freqn >> 10;
+		cp[2] = subs->freqn >> 18;
+	}
+	return 0;
+}
+
+/*
+ * prepare urb for high speed capture sync pipe
+ *
+ * fill the length and offset of each urb descriptor.
+ * the fixed 12.13 frequency is passed as 16.16 through the pipe.
+ */
+static int prepare_capture_sync_urb_hs(snd_usb_substream_t *subs,
+				       snd_pcm_runtime_t *runtime,
+				       struct urb *urb)
+{
+	unsigned char *cp = urb->transfer_buffer;
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+	int i, offs;
+
+	urb->number_of_packets = ctx->packets;
+	urb->dev = ctx->subs->dev; /* we need to set this at each time */
+	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4, cp += 4) {
+		urb->iso_frame_desc[i].length = 4;
+		urb->iso_frame_desc[i].offset = offs;
 		cp[0] = subs->freqn;
 		cp[1] = subs->freqn >> 8;
 		cp[2] = subs->freqn >> 16;
+		cp[3] = subs->freqn >> 24;
 	}
-	urb->interval = 1;
 	return 0;
 }
 
@@ -301,7 +349,6 @@
 	spin_unlock_irqrestore(&subs->lock, flags);
 	urb->transfer_buffer = ctx->buf;
 	urb->transfer_buffer_length = offs;
-	urb->interval = 1;
 #if 0 // for check
 	if (! urb->bandwidth) {
 		int bustime;
@@ -372,7 +419,7 @@
 
 
 /*
- * prepare urb for playback sync pipe
+ * prepare urb for full speed playback sync pipe
  *
  * set up the offset and length to receive the current frequency.
  */
@@ -386,16 +433,37 @@
 
 	urb->number_of_packets = ctx->packets;
 	urb->dev = ctx->subs->dev; /* we need to set this at each time */
-	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 3) {
+	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {
 		urb->iso_frame_desc[i].length = 3;
 		urb->iso_frame_desc[i].offset = offs;
 	}
-	urb->interval = 1;
 	return 0;
 }
 
 /*
- * process after playback sync complete
+ * prepare urb for high speed playback sync pipe
+ *
+ * set up the offset and length to receive the current frequency.
+ */
+
+static int prepare_playback_sync_urb_hs(snd_usb_substream_t *subs,
+					snd_pcm_runtime_t *runtime,
+					struct urb *urb)
+{
+	int i, offs;
+	snd_urb_ctx_t *ctx = (snd_urb_ctx_t *)urb->context;
+
+	urb->number_of_packets = ctx->packets;
+	urb->dev = ctx->subs->dev; /* we need to set this at each time */
+	for (i = offs = 0; i < urb->number_of_packets; i++, offs += 4) {
+		urb->iso_frame_desc[i].length = 4;
+		urb->iso_frame_desc[i].offset = offs;
+	}
+	return 0;
+}
+
+/*
+ * process after full speed playback sync complete
  *
  * retrieve the current 10.14 frequency from pipe, and set it.
  * the value is referred in prepare_playback_urb().
@@ -410,11 +478,11 @@
 	unsigned long flags;
 
 	found = 0;
-	for (i = 0; i < urb->number_of_packets; i++, cp += 3) {
+	for (i = 0; i < urb->number_of_packets; i++, cp += 4) {
 		if (urb->iso_frame_desc[i].status ||
 		    urb->iso_frame_desc[i].actual_length < 3)
 			continue;
-		f = combine_triple(cp);
+		f = combine_triple(cp) << 2;
 #if 0
 		if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) {
 			snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n",
@@ -435,6 +503,37 @@
 }
 
 /*
+ * process after high speed playback sync complete
+ *
+ * retrieve the current 12.13 frequency from pipe, and set it.
+ * the value is referred in prepare_playback_urb().
+ */
+static int retire_playback_sync_urb_hs(snd_usb_substream_t *subs,
+				       snd_pcm_runtime_t *runtime,
+				       struct urb *urb)
+{
+	int i;
+	unsigned int found;
+	unsigned char *cp = urb->transfer_buffer;
+	unsigned long flags;
+
+	found = 0;
+	for (i = 0; i < urb->number_of_packets; i++, cp += 4) {
+		if (urb->iso_frame_desc[i].status ||
+		    urb->iso_frame_desc[i].actual_length < 4)
+			continue;
+		found = combine_quad(cp) & 0x0fffffff;
+	}
+	if (found) {
+		spin_lock_irqsave(&subs->lock, flags);
+		subs->freqm = found;
+		spin_unlock_irqrestore(&subs->lock, flags);
+	}
+
+	return 0;
+}
+
+/*
  * prepare urb for playback data pipe
  *
  * we copy the data directly from the pcm buffer.
@@ -464,8 +563,8 @@
 		if (subs->fill_max)
 			counts = subs->maxframesize; /* fixed */
 		else {
-			subs->phase = (subs->phase & 0x3fff) + subs->freqm;
-			counts = subs->phase >> 14;
+			subs->phase = (subs->phase & 0xffff) + subs->freqm;
+			counts = subs->phase >> 16;
 			if (counts > subs->maxframesize)
 				counts = subs->maxframesize;
 		}
@@ -477,7 +576,7 @@
 		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;
@@ -515,7 +614,6 @@
 	spin_unlock_irqrestore(&subs->lock, flags);
 	urb->transfer_buffer_length = offs * stride;
 	ctx->transfer = offs;
-	urb->interval = 1;
 
 	return 0;
 }
@@ -565,6 +663,21 @@
 	},
 };
 
+static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
+	{
+		.prepare =	prepare_playback_urb,
+		.retire =	retire_playback_urb,
+		.prepare_sync =	prepare_playback_sync_urb_hs,
+		.retire_sync =	retire_playback_sync_urb_hs,
+	},
+	{
+		.prepare =	prepare_capture_urb,
+		.retire =	retire_capture_urb,
+		.prepare_sync =	prepare_capture_sync_urb_hs,
+		.retire_sync =	retire_capture_sync_urb,
+	},
+};
+
 /*
  * complete callback from data urb
  */
@@ -822,15 +935,19 @@
 {
 	unsigned int maxsize, n, i;
 	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
-	unsigned int npacks[MAX_URBS], total_packs;
+	unsigned int npacks[MAX_URBS], urb_packs, total_packs;
 
-	/* calculate the frequency in 10.14 format */
-	subs->freqn = subs->freqm = get_usb_rate(rate);
+	/* calculate the frequency in 16.16 format */
+	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+		subs->freqn = get_usb_full_speed_rate(rate);
+	else
+		subs->freqn = get_usb_high_speed_rate(rate);
+	subs->freqm = subs->freqn;
 	subs->freqmax = subs->freqn + (subs->freqn >> 2); /* max. allowed frequency */
 	subs->phase = 0;
 
 	/* calculate the max. size of packet */
-	maxsize = ((subs->freqmax + 0x3fff) * (frame_bits >> 3)) >> 14;
+	maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) >> 16;
 	if (subs->maxpacksize && maxsize > subs->maxpacksize) {
 		//snd_printd(KERN_DEBUG "maxsize %d is greater than defined size %d\n",
 		//	   maxsize, subs->maxpacksize);
@@ -842,9 +959,14 @@
 	else
 		subs->curpacksize = maxsize;
 
+	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+		urb_packs = nrpacks;
+	else
+		urb_packs = nrpacks * 8;
+
 	/* allocate a temporary buffer for playback */
 	if (is_playback) {
-		subs->tmpbuf = kmalloc(maxsize * nrpacks, GFP_KERNEL);
+		subs->tmpbuf = kmalloc(maxsize * urb_packs, GFP_KERNEL);
 		if (! subs->tmpbuf) {
 			snd_printk(KERN_ERR "cannot malloc tmpbuf\n");
 			return -ENOMEM;
@@ -855,16 +977,16 @@
 	total_packs = (period_bytes + maxsize - 1) / maxsize;
 	if (total_packs < 2 * MIN_PACKS_URB)
 		total_packs = 2 * MIN_PACKS_URB;
-	subs->nurbs = (total_packs + nrpacks - 1) / nrpacks;
+	subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
 	if (subs->nurbs > MAX_URBS) {
 		/* too much... */
 		subs->nurbs = MAX_URBS;
-		total_packs = MAX_URBS * nrpacks;
+		total_packs = MAX_URBS * urb_packs;
 	}
 	n = total_packs;
 	for (i = 0; i < subs->nurbs; i++) {
-		npacks[i] = n > nrpacks ? nrpacks : n;
-		n -= nrpacks;
+		npacks[i] = n > urb_packs ? urb_packs : n;
+		n -= urb_packs;
 	}
 	if (subs->nurbs <= 1) {
 		/* too little - we need at least two packets
@@ -894,7 +1016,7 @@
 		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 */
@@ -913,6 +1035,7 @@
 		u->urb->pipe = subs->datapipe;
 		u->urb->transfer_flags = URB_ISO_ASAP;
 		u->urb->number_of_packets = u->packets;
+		u->urb->interval = 1;
 		u->urb->context = u;
 		u->urb->complete = snd_usb_complete_callback(snd_complete_urb);
 	}
@@ -929,12 +1052,16 @@
 				release_substream_urbs(subs, 0);
 				return -ENOMEM;
 			}
-			u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 3;
-			u->urb->transfer_buffer_length = nrpacks * 3;
+			u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 4;
+			u->urb->transfer_buffer_length = nrpacks * 4;
 			u->urb->dev = subs->dev;
 			u->urb->pipe = subs->syncpipe;
 			u->urb->transfer_flags = URB_ISO_ASAP;
 			u->urb->number_of_packets = u->packets;
+			if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
+				u->urb->interval = 8;
+			else
+				u->urb->interval = 1;
 			u->urb->context = u;
 			u->urb->complete = snd_usb_complete_callback(snd_complete_sync_urb);
 		}
@@ -1074,7 +1201,6 @@
 static int set_format(snd_usb_substream_t *subs, struct audioformat *fmt)
 {
 	struct usb_device *dev = subs->dev;
-	struct usb_host_config *config = dev->actconfig;
 	struct usb_host_interface *alts;
 	struct usb_interface_descriptor *altsd;
 	struct usb_interface *iface;
@@ -1082,7 +1208,8 @@
 	int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
 	int err;
 
-	iface = get_iface(config, fmt->iface);
+	iface = usb_ifnum_to_if(dev, fmt->iface);
+	snd_assert(iface, return -EINVAL);
 	alts = &iface->altsetting[fmt->altset_idx];
 	altsd = get_iface_desc(alts);
 	snd_assert(altsd->bAlternateSetting == fmt->altsetting, return -EINVAL);
@@ -1099,7 +1226,7 @@
 
 	/* set interface */
 	if (subs->interface != fmt->iface || subs->format != fmt->altset_idx) {
-		if (usb_set_interface(dev, fmt->iface, fmt->altset_idx) < 0) {
+		if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) {
 			snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
 				   dev->devnum, fmt->iface, fmt->altsetting);
 			return -EIO;
@@ -1116,7 +1243,7 @@
 	else
 		subs->datapipe = usb_rcvisocpipe(dev, ep);
 	subs->syncpipe = subs->syncinterval = 0;
-	subs->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
+	subs->maxpacksize = fmt->maxpacksize;
 	subs->fill_max = 0;
 
 	/* we need a sync pipe in async OUT or adaptive IN mode */
@@ -1129,15 +1256,20 @@
 	     (! 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;
@@ -1208,10 +1340,9 @@
 		return ret;
 
 	if (subs->cur_rate != rate) {
-		struct usb_host_config *config = subs->dev->actconfig;
 		struct usb_host_interface *alts;
 		struct usb_interface *iface;
-		iface = get_iface(config, fmt->iface);
+		iface = usb_ifnum_to_if(subs->dev, fmt->iface);
 		alts = &iface->altsetting[fmt->altset_idx];
 		ret = init_usb_sample_rate(subs->dev, subs->interface, alts, fmt, rate);
 		if (ret < 0)
@@ -1588,7 +1719,7 @@
 			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 +1963,10 @@
 			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 = %u Hz\n",
+			    snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
+			    ? get_full_speed_hz(subs->freqm)
+			    : get_high_speed_hz(subs->freqm));
 	} else {
 		snd_iprintf(buffer, "  Status: Stop\n");
 	}
@@ -1884,9 +2016,14 @@
 	subs->stream = as;
 	subs->direction = stream;
 	subs->dev = as->chip->dev;
-	subs->ops = audio_urb_ops[stream];
+	if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+		subs->ops = audio_urb_ops[stream];
+	else
+		subs->ops = audio_urb_ops_high_speed[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 +2032,7 @@
 	subs->formats |= 1ULL << fp->format;
 	subs->endpoint = fp->endpoint;
 	subs->num_formats++;
-	subs->nonaudio = fp->nonaudio;
+	subs->fmt_type = fp->fmt_type;
 }
 
 
@@ -1954,17 +2091,12 @@
 
 	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 +2106,8 @@
 	/* 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 +2125,7 @@
 	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 +2351,6 @@
 		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 +2376,7 @@
 			   dev->devnum, fp->iface, fp->altsetting, fmt[3]);
 		return -1;
 	}
+	fp->fmt_type = fmt[3];
 	if (err < 0)
 		return err;
 #if 1
@@ -2262,7 +2397,6 @@
 static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no)
 {
 	struct usb_device *dev;
-	struct usb_host_config *config;
 	struct usb_interface *iface;
 	struct usb_host_interface *alts;
 	struct usb_interface_descriptor *altsd;
@@ -2272,10 +2406,9 @@
 	unsigned char *fmt, *csep;
 
 	dev = chip->dev;
-	config = dev->actconfig;
 
 	/* parse the interface's altsettings */
-	iface = get_iface(config, iface_no);
+	iface = usb_ifnum_to_if(dev, iface_no);
 	for (i = 0; i < iface->num_altsetting; i++) {
 		alts = &iface->altsetting[i];
 		altsd = get_iface_desc(alts);
@@ -2326,6 +2459,9 @@
 		}
 
 		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);
@@ -2344,6 +2480,7 @@
 		fp->altset_idx = i;
 		fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
 		fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
+		/* FIXME: decode wMaxPacketSize of high bandwith endpoints */
 		fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
 		fp->attributes = csep[3];
 
@@ -2398,7 +2535,7 @@
 			return err;
 		}
 		/* try to set the interface... */
-		usb_set_interface(chip->dev, iface_no, i);
+		usb_set_interface(chip->dev, iface_no, altno);
 		init_usb_pitch(chip->dev, iface_no, alts, fp);
 		init_usb_sample_rate(chip->dev, iface_no, alts, fp, fp->rate_max);
 	}
@@ -2415,7 +2552,6 @@
 	int idx;
 	snd_usb_stream_t *as;
 	snd_usb_substream_t *subs;
-	struct list_head *p;
 
 	as = list_entry(head, snd_usb_stream_t, list);
 	for (idx = 0; idx < 2; idx++) {
@@ -2424,11 +2560,6 @@
 			return;
 		release_substream_urbs(subs, 1);
 		subs->interface = -1;
-		/* release interfaces */
-		list_for_each(p, &subs->fmt_list) {
-			struct audioformat *fp = list_entry(p, struct audioformat, list);
-			usb_driver_release_interface(driver, usb_ifnum_to_if(subs->dev, fp->iface));
-		}
 	}
 }
 
@@ -2438,15 +2569,13 @@
 static int snd_usb_create_streams(snd_usb_audio_t *chip, int ctrlif)
 {
 	struct usb_device *dev = chip->dev;
-	struct usb_host_config *config;
 	struct usb_host_interface *host_iface;
 	struct usb_interface *iface;
 	unsigned char *p1;
 	int i, j;
 
 	/* find audiocontrol interface */
-	config = dev->actconfig;
-	host_iface = &get_iface(config, ctrlif)->altsetting[0];
+	host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
 	if (!(p1 = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, NULL, HEADER))) {
 		snd_printk(KERN_ERR "cannot find HEADER\n");
 		return -EINVAL;
@@ -2463,12 +2592,12 @@
 		struct usb_host_interface *alts;
 		struct usb_interface_descriptor *altsd;
 		j = p1[8 + i];
-		if (j >= get_cfg_desc(config)->bNumInterfaces) {
+		iface = usb_ifnum_to_if(dev, j);
+		if (!iface) {
 			snd_printk(KERN_ERR "%d:%u:%d : does not exist\n",
 				   dev->devnum, ctrlif, j);
 			continue;
 		}
-		iface = get_iface(config, j);
 		if (usb_interface_claimed(iface)) {
 			snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, j);
 			continue;
@@ -2525,6 +2654,11 @@
 		kfree(fp);
 		return err;
 	}
+	if (fp->iface != get_iface_desc(&iface->altsetting[0])->bInterfaceNumber ||
+	    fp->altset_idx >= iface->num_altsetting) {
+		kfree(fp);
+		return -EINVAL;
+	}
 	alts = &iface->altsetting[fp->altset_idx];
 	usb_set_interface(chip->dev, fp->iface, 0);
 	init_usb_pitch(chip->dev, fp->iface, alts, fp);
@@ -2577,14 +2711,13 @@
 				  struct usb_interface *iface,
 				  const snd_usb_audio_quirk_t *quirk)
 {
-	struct usb_host_config *config = chip->dev->actconfig;
 	int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
 	int err;
 
 	for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) {
-		if (quirk->ifnum >= get_cfg_desc(config)->bNumInterfaces)
+		iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
+		if (!iface)
 			continue;
-		iface = get_iface(config, quirk->ifnum);
 		if (quirk->ifnum != probed_ifnum &&
 		    usb_interface_claimed(iface))
 			continue;
@@ -2696,9 +2829,6 @@
 
 static int snd_usb_audio_free(snd_usb_audio_t *chip)
 {
-	down(&register_mutex);
-	usb_chip[chip->index] = NULL;
-	up(&register_mutex);
 	snd_magic_kfree(chip);
 	return 0;
 }
@@ -2713,10 +2843,11 @@
 /*
  * create a chip instance and set its names.
  */
-static int snd_usb_audio_create(snd_card_t *card, struct usb_device *dev,
+static int snd_usb_audio_create(struct usb_device *dev, int idx,
 				const snd_usb_audio_quirk_t *quirk,
 				snd_usb_audio_t **rchip)
 {
+	snd_card_t *card;
 	snd_usb_audio_t *chip;
 	int err, len;
 	char component[14];
@@ -2725,10 +2856,26 @@
 	};
 	
 	*rchip = NULL;
+
+	if (snd_usb_get_speed(dev) != USB_SPEED_FULL &&
+	    snd_usb_get_speed(dev) != USB_SPEED_HIGH) {
+		snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
+		return -ENXIO;
+	}
+
+	card = snd_card_new(index[idx], id[idx], THIS_MODULE, 0);
+	if (card == NULL) {
+		snd_printk(KERN_ERR "cannot create card instance %d\n", idx);
+		return -ENOMEM;
+	}
+
 	chip = snd_magic_kcalloc(snd_usb_audio_t, 0, GFP_KERNEL);
-	if (! chip)
+	if (! chip) {
+		snd_card_free(card);
 		return -ENOMEM;
+	}
 
+	chip->index = idx;
 	chip->dev = dev;
 	chip->card = card;
 	INIT_LIST_HEAD(&chip->pcm_list);
@@ -2736,6 +2883,7 @@
 
 	if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
 		snd_usb_audio_free(chip);
+		snd_card_free(card);
 		return err;
 	}
 
@@ -2778,6 +2926,10 @@
 	if (len < sizeof(card->longname))
 		usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
 
+	strlcat(card->longname,
+		snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : ", high speed",
+		sizeof(card->longname));
+
 	snd_usb_audio_create_proc(chip);
 
 	snd_card_set_dev(card, &dev->dev);
@@ -2804,7 +2956,6 @@
 	struct usb_host_config *config = dev->actconfig;
 	const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info;
 	int i, err;
-	snd_card_t *card;
 	snd_usb_audio_t *chip;
 	struct usb_host_interface *alts;
 	int ifnum;
@@ -2832,11 +2983,11 @@
 	down(&register_mutex);
 	for (i = 0; i < SNDRV_CARDS; i++) {
 		if (usb_chip[i] && usb_chip[i]->dev == dev) {
-			chip = usb_chip[i];
-			if (chip->shutdown) {
+			if (usb_chip[i]->shutdown) {
 				snd_printk(KERN_ERR "USB device is in the shutdown state, cannot create a card instance\n");
 				goto __error;
 			}
+			chip = usb_chip[i];
 			break;
 		}
 	}
@@ -2853,17 +3004,9 @@
 			if (enable[i] && ! usb_chip[i] &&
 			    (vid[i] == -1 || vid[i] == dev->descriptor.idVendor) &&
 			    (pid[i] == -1 || pid[i] == dev->descriptor.idProduct)) {
-				card = snd_card_new(index[i], id[i], THIS_MODULE, 0);
-				if (card == NULL) {
-					snd_printk(KERN_ERR "cannot create a card instance %d\n", i);
-					goto __error;
-				}
-				if (snd_usb_audio_create(card, dev, quirk, &chip) < 0) {
-					snd_card_free(card);
+				if (snd_usb_audio_create(dev, i, quirk, &chip) < 0) {
 					goto __error;
 				}
-				chip->index = i;
-				usb_chip[i] = chip;
 				break;
 			}
 		if (! chip) {
@@ -2889,16 +3032,17 @@
 
 	/* we are allowed to call snd_card_register() many times */
 	if (snd_card_register(chip->card) < 0) {
-		if (! chip->num_interfaces)
-			snd_card_free(chip->card);
 		goto __error;
 	}
 
+	usb_chip[chip->index] = chip;
 	chip->num_interfaces++;
 	up(&register_mutex);
 	return chip;
 
  __error:
+	if (chip && !chip->num_interfaces)
+		snd_card_free(chip->card);
 	up(&register_mutex);
  __err_val:
 	return NULL;
@@ -2932,6 +3076,7 @@
 		list_for_each(p, &chip->midi_list) {
 			snd_usbmidi_disconnect(p, &usb_audio_driver);
 		}
+		usb_chip[chip->index] = NULL;
 		up(&register_mutex);
 		snd_card_free_in_thread(card);
 	} else {
@@ -2963,7 +3108,7 @@
 
 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 -Nru a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
--- a/sound/usb/usbaudio.h	Sat Apr  3 19:38:44 2004
+++ b/sound/usb/usbaudio.h	Sat Apr  3 19:38:44 2004
@@ -136,6 +136,8 @@
 
 	struct list_head midi_list;	/* list of midi interfaces */
 	int next_midi_device;
+
+	unsigned int ignore_ctl_error;	/* for mixer */
 };  
 
 /*
@@ -205,8 +207,7 @@
  * (conditional for compatibility with the older API)
  */
 #ifndef get_iface_desc
-#define get_iface(cfg, num)	((cfg)->interface[(num)])
-#define get_iface_desc(iface)	(&iface->desc)
+#define get_iface_desc(iface)	(&(iface)->desc)
 #define get_endpoint(alt,ep)	(&(alt)->endpoint[ep].desc)
 #define get_ep_desc(ep)		(&(ep)->desc)
 #define get_cfg_desc(cfg)	(&(cfg)->desc)
@@ -218,6 +219,10 @@
 
 #ifndef snd_usb_complete_callback
 #define snd_usb_complete_callback(x) (x)
+#endif
+
+#ifndef snd_usb_get_speed
+#define snd_usb_get_speed(dev) ((dev)->speed)
 #endif
 
 #endif /* __USBAUDIO_H */
diff -Nru a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
--- a/sound/usb/usbmidi.c	Sat Apr  3 19:38:55 2004
+++ b/sound/usb/usbmidi.c	Sat Apr  3 19:38:55 2004
@@ -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,
@@ -143,8 +143,9 @@
 	if (status == -ENOENT)
 		return status; /* killed */
 	if (status == -EILSEQ ||
+	    status == -ECONNRESET ||
 	    status == -ETIMEDOUT)
-		return -ENODEV; /* device removed */
+		return -ENODEV; /* device removed/shutdown */
 	snd_printk(KERN_ERR "urb status %d\n", status);
 	return 0; /* continue */
 }
@@ -453,8 +454,16 @@
 	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)
@@ -698,7 +707,6 @@
 	int i;
 
 	umidi = list_entry(p, snd_usb_midi_t, list);
-	usb_driver_release_interface(driver, umidi->iface);
 	for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
 		snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
 		if (ep->out && ep->out->urb)
@@ -727,18 +735,118 @@
 	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;
 }
 
@@ -906,6 +1014,10 @@
 	if (intfd->bNumEndpoints < 1)
 		return -ENOENT;
 
+	/*
+	 * For each port there is one MIDI_IN/OUT_JACK descriptor, not
+	 * necessarily with any useful contents.  So simply count 'em.
+	 */
 	for (cs_desc = hostif->extra;
 	     cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
 	     cs_desc += cs_desc[0]) {
@@ -940,6 +1052,16 @@
 		return -ENOENT;
 	hostif = intf->altsetting;
 	intfd = get_iface_desc(hostif);
+	/*
+	 * The various MidiSport devices have more or less random endpoint
+	 * numbers, so we have to identify the endpoints by their index in
+	 * the descriptor array, like the driver for that other OS does.
+	 *
+	 * There is one interrupt input endpoint for all input ports, one
+	 * bulk output endpoint for even-numbered ports, and one for odd-
+	 * numbered ports.  Both bulk output endpoints have corresponding
+	 * input bulk endpoints (at indices 1 and 3) which aren't used.
+	 */
 	if (intfd->bNumEndpoints < (endpoint->out_cables > 0x0001 ? 5 : 3)) {
 		snd_printdd(KERN_ERR "not enough endpoints\n");
 		return -ENOENT;
diff -Nru a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
--- a/sound/usb/usbmixer.c	Sat Apr  3 19:38:42 2004
+++ b/sound/usb/usbmixer.c	Sat Apr  3 19:38:42 2004
@@ -667,13 +667,11 @@
 		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 @@
 	} 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 @@
 		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 @@
 	} 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 @@
 	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 @@
 	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 @@
 	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 @@
 	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) {
@@ -1493,7 +1481,7 @@
 	int err;
 	const struct usbmix_ctl_map *map;
 	struct usb_device_descriptor *dev = &chip->dev->descriptor;
-	struct usb_host_interface *hostif = &get_iface(chip->dev->actconfig, ctrlif)->altsetting[0];
+	struct usb_host_interface *hostif = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0];
 
 	strcpy(chip->card->mixername, "USB Mixer");
 
@@ -1509,9 +1497,13 @@
 	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 -Nru a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c
--- a/sound/usb/usbmixer_maps.c	Sat Apr  3 19:38:56 2004
+++ b/sound/usb/usbmixer_maps.c	Sat Apr  3 19:38:56 2004
@@ -30,6 +30,7 @@
 	int vendor;
 	int product;
 	const struct usbmix_name_map *map;
+	int ignore_ctl_error;
 };
 	
 /*
@@ -86,6 +87,7 @@
 	{ 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_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 -Nru a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
--- a/sound/usb/usbquirks.h	Sat Apr  3 19:38:43 2004
+++ b/sound/usb/usbquirks.h	Sat Apr  3 19:38:43 2004
@@ -104,7 +104,7 @@
 #undef YAMAHA_INTERFACE
 
 /*
- * Roland/RolandED/Edirol devices
+ * Roland/RolandED/Edirol/BOSS devices
  */
 {
 	USB_DEVICE(0x0582, 0x0000),
@@ -196,8 +196,8 @@
 		.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 @@
 	}
 },
 {
+	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 @@
 	}
 },
 {
+	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 @@
 	}
 },
 {
+	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",
@@ -686,6 +829,16 @@
 		.ifnum = QUIRK_NO_INTERFACE
 	}
 	
+},
+
+{
+	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
